diff options
| author | nyamatongwe <unknown> | 2009-05-14 12:38:27 +0000 | 
|---|---|---|
| committer | nyamatongwe <unknown> | 2009-05-14 12:38:27 +0000 | 
| commit | dbf6ed4d115282451b88844e8a8c75dccb9aec4a (patch) | |
| tree | 655e5ba85b730eb189f54d8159b0e3fac99e44bf | |
| parent | 56b8f2fb26d5c518712796a9832c3d43ea570c58 (diff) | |
| download | scintilla-mirror-dbf6ed4d115282451b88844e8a8c75dccb9aec4a.tar.gz | |
Updated MySQL lexer from Mike Lischke at Sun.
Adds SCE_MYSQL_HIDDENCOMMAND.
List of keyword names terminated with 0.
| -rw-r--r-- | include/SciLexer.h | 1 | ||||
| -rw-r--r-- | include/Scintilla.iface | 1 | ||||
| -rw-r--r-- | src/LexMySQL.cxx | 639 | 
3 files changed, 381 insertions, 260 deletions
| diff --git a/include/SciLexer.h b/include/SciLexer.h index 56c9cbdc5..38f5d0de6 100644 --- a/include/SciLexer.h +++ b/include/SciLexer.h @@ -1270,6 +1270,7 @@  #define SCE_MYSQL_USER1 18  #define SCE_MYSQL_USER2 19  #define SCE_MYSQL_USER3 20 +#define SCE_MYSQL_HIDDENCOMMAND 21  #define SCE_PO_DEFAULT 0  #define SCE_PO_COMMENT 1  #define SCE_PO_MSGID 2 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index 9c9eeb1be..97cf8ac16 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -3450,6 +3450,7 @@ val SCE_MYSQL_QUOTEDIDENTIFIER=17  val SCE_MYSQL_USER1=18  val SCE_MYSQL_USER2=19  val SCE_MYSQL_USER3=20 +val SCE_MYSQL_HIDDENCOMMAND=21  # Lexical state for SCLEX_PO  lex Po=SCLEX_PO SCE_PO_  val SCE_PO_DEFAULT=0 diff --git a/src/LexMySQL.cxx b/src/LexMySQL.cxx index 742ff4339..b6d7135b1 100644 --- a/src/LexMySQL.cxx +++ b/src/LexMySQL.cxx @@ -1,11 +1,14 @@ -// Scintilla source code edit control -/** @file LexMySQL.cxx - ** Lexer for MySQL - **/ -// Adopted from LexSQL.cxx by Anders Karlsson <anders@mysql.com> -// Original work by Neil Hodgson <neilh@scintilla.org> -// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org> -// The License.txt file describes the conditions under which this software may be distributed. +/** + * Scintilla source code edit control + * @file LexMySQL.cxx + * Lexer for MySQL + * + * Improved by Mike Lischke <mike.lischke@sun.com> + * Adopted from LexSQL.cxx by Anders Karlsson <anders@mysql.com> + * Original work by Neil Hodgson <neilh@scintilla.org> + * Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org> + * The License.txt file describes the conditions under which this software may be distributed. + */  #include <stdlib.h>  #include <string.h> @@ -49,287 +52,400 @@ static inline bool IsANumberChar(int ch) {               ch == '.' || ch == '-' || ch == '+');  } -static void ColouriseMySQLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], -                            Accessor &styler) { +//-------------------------------------------------------------------------------------------------- + +/** + * Check if the current content context represent a keyword and set the context state if so. + */ +static void CheckForKeyword(StyleContext& sc, WordList* keywordlists[]) +{ +  int length = sc.LengthCurrent() + 1; // +1 for the next char +  char* s = new char[length]; +  sc.GetCurrentLowered(s, length); +  if (keywordlists[0]->InList(s)) +    sc.ChangeState(SCE_MYSQL_MAJORKEYWORD); +  else +    if (keywordlists[1]->InList(s)) +      sc.ChangeState(SCE_MYSQL_KEYWORD); +    else +      if (keywordlists[2]->InList(s)) +        sc.ChangeState(SCE_MYSQL_DATABASEOBJECT); +      else +        if (keywordlists[3]->InList(s)) +          sc.ChangeState(SCE_MYSQL_FUNCTION); +        else +          if (keywordlists[5]->InList(s)) +            sc.ChangeState(SCE_MYSQL_PROCEDUREKEYWORD); +          else +            if (keywordlists[6]->InList(s)) +              sc.ChangeState(SCE_MYSQL_USER1); +            else +              if (keywordlists[7]->InList(s)) +                sc.ChangeState(SCE_MYSQL_USER2); +              else +                if (keywordlists[8]->InList(s)) +                  sc.ChangeState(SCE_MYSQL_USER3); +  delete [] s; +} -	WordList &major_keywords = *keywordlists[0]; -	WordList &keywords = *keywordlists[1]; -	WordList &database_objects = *keywordlists[2]; -	WordList &functions = *keywordlists[3]; -	WordList &system_variables = *keywordlists[4]; -	WordList &procedure_keywords = *keywordlists[5]; -	WordList &kw_user1 = *keywordlists[6]; -	WordList &kw_user2 = *keywordlists[7]; -	WordList &kw_user3 = *keywordlists[8]; +//-------------------------------------------------------------------------------------------------- +static void ColouriseMySQLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], +                            Accessor &styler) +{  	StyleContext sc(startPos, length, initStyle, styler); -	for (; sc.More(); sc.Forward()) { +	for (; sc.More(); sc.Forward()) +  {  		// Determine if the current state should terminate. -		switch (sc.state) { -		case SCE_MYSQL_OPERATOR: -			sc.SetState(SCE_MYSQL_DEFAULT); -			break; -		case SCE_MYSQL_NUMBER: -			// We stop the number definition on non-numerical non-dot non-eE non-sign char -			if (!IsANumberChar(sc.ch)) { -				sc.SetState(SCE_MYSQL_DEFAULT); -			} -			break; -		case SCE_MYSQL_IDENTIFIER: -			if (!IsAWordChar(sc.ch)) { -				int nextState = SCE_MYSQL_DEFAULT; -				char s[1000]; -				sc.GetCurrentLowered(s, sizeof(s)); -				if (major_keywords.InList(s)) { -					sc.ChangeState(SCE_MYSQL_MAJORKEYWORD); -				} else if (keywords.InList(s)) { -					sc.ChangeState(SCE_MYSQL_KEYWORD); -				} else if (database_objects.InList(s)) { -					sc.ChangeState(SCE_MYSQL_DATABASEOBJECT); -				} else if (functions.InList(s)) { -					sc.ChangeState(SCE_MYSQL_FUNCTION); -				} else if (procedure_keywords.InList(s)) { -					sc.ChangeState(SCE_MYSQL_PROCEDUREKEYWORD); -				} else if (kw_user1.InList(s)) { -					sc.ChangeState(SCE_MYSQL_USER1); -				} else if (kw_user2.InList(s)) { -					sc.ChangeState(SCE_MYSQL_USER2); -				} else if (kw_user3.InList(s)) { -					sc.ChangeState(SCE_MYSQL_USER3); -				} -				sc.SetState(nextState); -			} -			break; -		case SCE_MYSQL_VARIABLE: -			if (!IsAWordChar(sc.ch)) { -				sc.SetState(SCE_MYSQL_DEFAULT); -			} -			break; -		case SCE_MYSQL_SYSTEMVARIABLE: -			if (!IsAWordChar(sc.ch)) { -				char s[1000]; -				sc.GetCurrentLowered(s, sizeof(s)); -// Check for known system variables here. -				if (system_variables.InList(&s[2])) { -					sc.ChangeState(SCE_MYSQL_KNOWNSYSTEMVARIABLE); -				} -				sc.SetState(SCE_MYSQL_DEFAULT); -			} -			break; -		case SCE_MYSQL_QUOTEDIDENTIFIER: -			if (sc.ch == 0x60) { -				if (sc.chNext == 0x60) { -					sc.Forward();	// Ignore it -				} else { -					sc.ForwardSetState(SCE_MYSQL_DEFAULT); -				} -			} -			break; -		case SCE_MYSQL_COMMENT: -			if (sc.Match('*', '/')) { -				sc.Forward(); -				sc.ForwardSetState(SCE_MYSQL_DEFAULT); -			} -			break; -		case SCE_MYSQL_COMMENTLINE: -			if (sc.atLineStart) { -				sc.SetState(SCE_MYSQL_DEFAULT); -			} -			break; -		case SCE_MYSQL_SQSTRING: -			if (sc.ch == '\\') { -				// Escape sequence -				sc.Forward(); -			} else if (sc.ch == '\'') { -				if (sc.chNext == '\'') { -					sc.Forward(); -				} else { -					sc.ChangeState(SCE_MYSQL_STRING); -					sc.ForwardSetState(SCE_MYSQL_DEFAULT); -				} -			} -			break; -		case SCE_MYSQL_DQSTRING: -			if (sc.ch == '\\') { -				// Escape sequence -				sc.Forward(); -			} else if (sc.ch == '\"') { -				if (sc.chNext == '\"') { -					sc.Forward(); -				} else { -					sc.ChangeState(SCE_MYSQL_STRING); -					sc.ForwardSetState(SCE_MYSQL_DEFAULT); +		switch (sc.state) +    { +      case SCE_MYSQL_OPERATOR: +        sc.SetState(SCE_MYSQL_DEFAULT); +        break; +      case SCE_MYSQL_NUMBER: +        // We stop the number definition on non-numerical non-dot non-eE non-sign char. +        if (!IsANumberChar(sc.ch)) +          sc.SetState(SCE_MYSQL_DEFAULT); +        break; +      case SCE_MYSQL_IDENTIFIER: +        // Switch from identifier to keyword state and open a new state for the new char. +        if (!IsAWordChar(sc.ch)) +        { +          CheckForKeyword(sc, keywordlists); +          sc.SetState(SCE_MYSQL_DEFAULT); +        } +        break; +      case SCE_MYSQL_VARIABLE: +        if (!IsAWordChar(sc.ch)) +          sc.SetState(SCE_MYSQL_DEFAULT); +        break; +      case SCE_MYSQL_SYSTEMVARIABLE: +        if (!IsAWordChar(sc.ch)) +        { +          int length = sc.LengthCurrent() + 1; +          char* s = new char[length]; +          sc.GetCurrentLowered(s, length); + +          // Check for known system variables here. +          if (keywordlists[4]->InList(&s[2])) +            sc.ChangeState(SCE_MYSQL_KNOWNSYSTEMVARIABLE); +          delete [] s; +           +          sc.SetState(SCE_MYSQL_DEFAULT); +        } +        break; +      case SCE_MYSQL_QUOTEDIDENTIFIER: +        if (sc.ch == '`') +        { +          if (sc.chNext == '`') +            sc.Forward();	// Ignore it +          else +            sc.ForwardSetState(SCE_MYSQL_DEFAULT);  				} -			} -			break; -		} +  			break; +      case SCE_MYSQL_COMMENT: +      case SCE_MYSQL_HIDDENCOMMAND: +        if (sc.Match('*', '/')) +        { +          sc.Forward(); +          sc.ForwardSetState(SCE_MYSQL_DEFAULT); +        } +        break; +      case SCE_MYSQL_COMMENTLINE: +        if (sc.atLineStart) +          sc.SetState(SCE_MYSQL_DEFAULT); +        break; +      case SCE_MYSQL_SQSTRING: +        if (sc.ch == '\\') +          sc.Forward(); // Escape sequence +        else +          if (sc.ch == '\'') +          { +            // End of single quoted string reached? +            if (sc.chNext == '\'') +              sc.Forward(); +            else +              sc.ForwardSetState(SCE_MYSQL_DEFAULT); +          } +        break; +      case SCE_MYSQL_DQSTRING: +        if (sc.ch == '\\') +          sc.Forward(); // Escape sequence +        else +          if (sc.ch == '\"') +          { +            // End of single quoted string reached? +            if (sc.chNext == '\"') +              sc.Forward(); +            else +              sc.ForwardSetState(SCE_MYSQL_DEFAULT); +          } +        break; +    } -		// Determine if a new state should be entered. -		if (sc.state == SCE_MYSQL_DEFAULT) { -			if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { -				sc.SetState(SCE_MYSQL_NUMBER); -			} else if (IsAWordStart(sc.ch)) { -				sc.SetState(SCE_MYSQL_IDENTIFIER); -// Note that the order of SYSTEMVARIABLE and VARIABLE is important here. -			} else if (sc.ch == 0x40 && sc.chNext == 0x40) { -				sc.SetState(SCE_MYSQL_SYSTEMVARIABLE); -				sc.Forward(); // Skip past the second at-sign. -			} else if (sc.ch == 0x40) { -				sc.SetState(SCE_MYSQL_VARIABLE); -			} else if (sc.ch == 0x60) { -				sc.SetState(SCE_MYSQL_QUOTEDIDENTIFIER); -			} else if (sc.Match('/', '*')) { -				sc.SetState(SCE_MYSQL_COMMENT); -				sc.Forward();	// Eat the * so it isn't used for the end of the comment -			} else if (sc.Match('-', '-') || sc.Match('#')) { -				sc.SetState(SCE_MYSQL_COMMENTLINE); -			} else if (sc.ch == '\'') { -				sc.SetState(SCE_MYSQL_SQSTRING); -			} else if (sc.ch == '\"') { -				sc.SetState(SCE_MYSQL_DQSTRING); -			} else if (isoperator(static_cast<char>(sc.ch))) { -				sc.SetState(SCE_MYSQL_OPERATOR); -			} -		} -	} -	sc.Complete(); +    // Determine if a new state should be entered. +    if (sc.state == SCE_MYSQL_DEFAULT) +    { +      switch (sc.ch) +      { +        case '@': +          if (sc.chNext == '@') +          { +            sc.SetState(SCE_MYSQL_SYSTEMVARIABLE); +            sc.Forward(2); // Skip past @@. +          } +          else +            if (IsAWordStart(sc.ch)) +            { +              sc.SetState(SCE_MYSQL_VARIABLE); +              sc.Forward(); // Skip past @. +            } +            else +              sc.SetState(SCE_MYSQL_OPERATOR); +          break; +        case '`': +          sc.SetState(SCE_MYSQL_QUOTEDIDENTIFIER); +          break; +        case '#': +          sc.SetState(SCE_MYSQL_COMMENTLINE); +          break; +        case '\'': +          sc.SetState(SCE_MYSQL_SQSTRING); +          break; +        case '\"': +          sc.SetState(SCE_MYSQL_DQSTRING); +          break; +        default: +          if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) +            sc.SetState(SCE_MYSQL_NUMBER); +          else +            if (IsAWordStart(sc.ch)) +              sc.SetState(SCE_MYSQL_IDENTIFIER); +            else +              if (sc.Match('/', '*')) +              { +                sc.SetState(SCE_MYSQL_COMMENT); +                 +                // Skip comment introducer and check for hidden command. +                sc.Forward(2); +                if (sc.ch == '!') +                { +                  sc.ChangeState(SCE_MYSQL_HIDDENCOMMAND); +                  sc.Forward(); +                } +              } +              else +                if (sc.Match("--")) +                { +                  // Special MySQL single line comment. +                  sc.SetState(SCE_MYSQL_COMMENTLINE); +                  sc.Forward(2); +                   +                  // Check the third character too. It must be a space or EOL. +                  if (sc.ch != ' ' && sc.ch != '\n' && sc.ch != '\r') +                    sc.ChangeState(SCE_MYSQL_OPERATOR); +                } +                else +                  if (isoperator(static_cast<char>(sc.ch))) +                    sc.SetState(SCE_MYSQL_OPERATOR); +      } +    } +  } +   +  // Do a final check for keywords if we currently have an identifier, to highlight them +  // also at the end of a line. +  if (sc.state == SCE_MYSQL_IDENTIFIER) +    CheckForKeyword(sc, keywordlists); +	 +  sc.Complete();  } -static bool IsStreamCommentStyle(int style) { +//-------------------------------------------------------------------------------------------------- + +/** + * Helper function to determine if we have a foldable comment currently. + */ +static bool IsStreamCommentStyle(int style) +{  	return style == SCE_MYSQL_COMMENT;  } +//-------------------------------------------------------------------------------------------------- +  // Store both the current line's fold level and the next lines in the  // level store to make it easy to pick up with each increment. -static void FoldMySQLDoc(unsigned int startPos, int length, int initStyle, -                            WordList *[], Accessor &styler) { +static void FoldMySQLDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) +{  	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;  	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;  	bool foldOnlyBegin = styler.GetPropertyInt("fold.sql.only.begin", 0) != 0; -	unsigned int endPos = startPos + length; +  StyleContext sc(startPos, length, initStyle, styler); +    	int visibleChars = 0;  	int lineCurrent = styler.GetLine(startPos);  	int levelCurrent = SC_FOLDLEVELBASE; -	if (lineCurrent > 0) { +	if (lineCurrent > 0)  		levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16; -	}  	int levelNext = levelCurrent; -	char chNext = styler[startPos]; +  	int styleNext = styler.StyleAt(startPos);  	int style = initStyle; -	bool endFound = false; +	 +  bool endFound = false;  	bool whenFound = false;  	bool elseFound = false; -	for (unsigned int i = startPos; i < endPos; i++) { -		char ch = chNext; -		chNext = styler.SafeGetCharAt(i + 1); +	 +  for (unsigned int i = startPos; sc.More(); i++, sc.Forward()) +  {  		int stylePrev = style;  		style = styleNext;  		styleNext = styler.StyleAt(i + 1); -		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); -		if (foldComment && IsStreamCommentStyle(style)) { -			if (!IsStreamCommentStyle(stylePrev)) { -				levelNext++; -			} else if (!IsStreamCommentStyle(styleNext) && !atEOL) { -				// Comments don't end at end of line and the next character may be unstyled. -				levelNext--; -			} -		} -		if (foldComment && (style == SCE_MYSQL_COMMENTLINE)) { -			// MySQL needs -- comments to be followed by space or control char -			if ((ch == '-') && (chNext == '-')) { -				char chNext2 = styler.SafeGetCharAt(i + 2); -				char chNext3 = styler.SafeGetCharAt(i + 3); -				if (chNext2 == '{' || chNext3 == '{') { -					levelNext++; -				} else if (chNext2 == '}' || chNext3 == '}') { -					levelNext--; -				} -			} -		} -		if (style == SCE_MYSQL_OPERATOR) { -			if (ch == '(') { -				levelNext++; -			} else if (ch == ')') { -				levelNext--; -			} -		} - -// Style new keywords here. -		if ((style == SCE_MYSQL_MAJORKEYWORD && stylePrev != SCE_MYSQL_MAJORKEYWORD) -		  || (style == SCE_MYSQL_KEYWORD && stylePrev != SCE_MYSQL_KEYWORD) -		  || (style == SCE_MYSQL_PROCEDUREKEYWORD && stylePrev != SCE_MYSQL_PROCEDUREKEYWORD)) { -			const int MAX_KW_LEN = 6;	// Maximum length of folding keywords -			char s[MAX_KW_LEN + 2]; -			unsigned int j = 0; -			for (; j < MAX_KW_LEN + 1; j++) { -				if (!iswordchar(styler[i + j])) { -					break; -				} -				s[j] = static_cast<char>(tolower(styler[i + j])); -			} -			if (j == MAX_KW_LEN + 1) { -				// Keyword too long, don't test it -				s[0] = '\0'; -			} else { -				s[j] = '\0'; -			} -			if (!foldOnlyBegin && endFound && (strcmp(s, "if") == 0 || strcmp(s, "while") == 0 || strcmp(s, "loop") == 0)) { -				endFound = false; -				levelNext--; -				if (levelNext < SC_FOLDLEVELBASE) { -					levelNext = SC_FOLDLEVELBASE; -				} -// Note that else is special here. It may or may be followed by an if then, but in aly case the level stays the -// same. When followed by a if .. then, the level will be increased later, if not, at eol. -			} else if (!foldOnlyBegin && strcmp(s, "else") == 0) { -				levelNext--; -				elseFound = true; -			} else if (!foldOnlyBegin && strcmp(s, "then") == 0) { -				if(whenFound) { -					whenFound = false; -				} else { -					levelNext++; -				} -			} else if (strcmp(s, "if") == 0) { -				elseFound = false; -			} else if (strcmp(s, "when") == 0) { -				whenFound = true; -			} else if (strcmp(s, "begin") == 0) { -				levelNext++; -			} else if (!foldOnlyBegin && (strcmp(s, "loop") == 0 || strcmp(s, "repeat") == 0 -			  || strcmp(s, "while") == 0)) { -				if(endFound) { -					endFound = false; -				} else { -					levelNext++; -				} -			} else if (strcmp(s, "end") == 0) { -// Multiple END in a row are counted multiple times! -				if (endFound) { -					levelNext--; -					if (levelNext < SC_FOLDLEVELBASE) { -						levelNext = SC_FOLDLEVELBASE; -					} -				} -				endFound = true; -				whenFound = false; -			} -		} -// Handle this for a trailing end withiut an if / while etc, as in the case of a begin. -		if (endFound) { +		bool atEOL = (sc.ch == '\r' && sc.chNext != '\n') || (sc.ch == '\n'); +	 +    switch (style) +    { +      case SCE_MYSQL_COMMENT: +        if (foldComment) +        { +          // Multiline comment style /* .. */. +          if (IsStreamCommentStyle(style)) +          { +            // Increase level if we just start a foldable comment. +            if (!IsStreamCommentStyle(stylePrev)) +              levelNext++; +            else +              // If we are in the middle of a foldable comment check if it ends now. +              // Don't end at the line end, though. +              if (!IsStreamCommentStyle(styleNext) && !atEOL) +                levelNext--; +          } +        } +        break; +      case SCE_MYSQL_COMMENTLINE: +        if (foldComment) +        {  +          // Not really a standard, but we add support for single line comments +          // with special curly braces syntax as foldable comments too. +          // MySQL needs -- comments to be followed by space or control char +          if (sc.Match('-', '-')) +          { +            char chNext2 = styler.SafeGetCharAt(i + 2); +            char chNext3 = styler.SafeGetCharAt(i + 3); +            if (chNext2 == '{' || chNext3 == '{') +              levelNext++; +            else +              if (chNext2 == '}' || chNext3 == '}') +                levelNext--; +          } +        } +        break; +      case SCE_MYSQL_HIDDENCOMMAND: +        if (style != stylePrev) +          levelNext++; +        else +          if (style != styleNext) +            levelNext--; +        break; +      case SCE_MYSQL_OPERATOR: +        if (sc.ch == '(') +          levelNext++; +        else +          if (sc.ch == ')') +            levelNext--; +        break; +      case SCE_MYSQL_MAJORKEYWORD: +      case SCE_MYSQL_KEYWORD: +      case SCE_MYSQL_FUNCTION: +      case SCE_MYSQL_PROCEDUREKEYWORD: +        // Reserved and other keywords. +        if (style != stylePrev) +        { +          bool beginFound = sc.MatchIgnoreCase("begin"); +          bool ifFound = sc.MatchIgnoreCase("if"); +          bool thenFound = sc.MatchIgnoreCase("then"); +          bool whileFound = sc.MatchIgnoreCase("while"); +          bool loopFound = sc.MatchIgnoreCase("loop"); +          bool repeatFound = sc.MatchIgnoreCase("repeat"); +           +          if (!foldOnlyBegin && endFound && (ifFound || whileFound || loopFound)) +          { +            endFound = false; +            levelNext--; +            if (levelNext < SC_FOLDLEVELBASE) +              levelNext = SC_FOLDLEVELBASE; +             +            // Note that "else" is special here. It may or may not be followed by an "if .. then", +            // but in any case the level stays the same. When followed by an "if .. then" the level +            // will be increased later, if not, then at eol. +          } +          else +            if (!foldOnlyBegin && sc.MatchIgnoreCase("else")) +            { +              levelNext--; +              elseFound = true; +            } +            else +              if (!foldOnlyBegin && thenFound) +              { +                if (whenFound) +                  whenFound = false; +                else +                  levelNext++; +              } +              else +                if (ifFound) +                  elseFound = false; +                else +                  if (sc.MatchIgnoreCase("when")) +                    whenFound = true; +                  else +                  { +                    if (beginFound) +                      levelNext++; +                    else +                      if (!foldOnlyBegin && (loopFound || repeatFound || whileFound)) +                      { +                        if (endFound) +                          endFound = false; +                        else +                          levelNext++; +                      } +                      else +                        if (sc.MatchIgnoreCase("end")) +                        { +                          // Multiple "end" in a row are counted multiple times! +                          if (endFound) +                          { +                            levelNext--; +                            if (levelNext < SC_FOLDLEVELBASE) +                              levelNext = SC_FOLDLEVELBASE; +                          } +                          endFound = true; +                          whenFound = false; +                        } +                  } +        } +        break; +    } +     +    // Handle the case of a trailing end without an if / while etc, as in the case of a begin. +		if (endFound) +    {  			endFound = false;  			levelNext--; -			if (levelNext < SC_FOLDLEVELBASE) { -				levelNext = SC_FOLDLEVELBASE; -			} +			if (levelNext < SC_FOLDLEVELBASE) +        levelNext = SC_FOLDLEVELBASE;  		} -		if (atEOL) { -			if(elseFound) +     +		if (atEOL) +    { +			if (elseFound) +      {  				levelNext++; -			elseFound = false; +        elseFound = false; +      }  			int levelUse = levelCurrent;  			int lev = levelUse | levelNext << 16; @@ -337,21 +453,23 @@ static void FoldMySQLDoc(unsigned int startPos, int length, int initStyle,  				lev |= SC_FOLDLEVELWHITEFLAG;  			if (levelUse < levelNext)  				lev |= SC_FOLDLEVELHEADERFLAG; -			if (lev != styler.LevelAt(lineCurrent)) { +			if (lev != styler.LevelAt(lineCurrent))  				styler.SetLevel(lineCurrent, lev); -			} +        			lineCurrent++;  			levelCurrent = levelNext;  			visibleChars = 0;  			endFound = false;  			whenFound = false;  		} -		if (!isspacechar(ch)) { +     +		if (!isspacechar(static_cast<char>(sc.ch)))  			visibleChars++; -		}  	}  } +//-------------------------------------------------------------------------------------------------- +  static const char * const mysqlWordListDesc[] = {  	"Major Keywords",  	"Keywords", @@ -361,7 +479,8 @@ static const char * const mysqlWordListDesc[] = {  	"Procedure keywords",  	"User Keywords 1",  	"User Keywords 2", -	"User Keywords 3" +	"User Keywords 3", +	0  };  LexerModule lmMySQL(SCLEX_MYSQL, ColouriseMySQLDoc, "mysql", FoldMySQLDoc, mysqlWordListDesc); | 
