notepad-plus-plus-legacy/scintilla/lexers/LexUser.cxx
Markus Heidelberg 6dab6621ba
Make Scintilla build properly with GCC/MinGW
Fix GCC compile error: extra qualification 'WordList::' on member 'SetWordAt' [-fpermissive]

Fix GCC compile error: a storage class can only be specified for objects and functions

Fix GCC compile error with invalid usage of conditional operator
  Invoke the "afterthought" part of the for loop in the normal code at the
  end of the loop where proper conditions can be used.
  Error message:
  third operand to the conditional operator is of type 'void', but the second operand
  is neither a throw-expression nor of type 'void'

closes #1656
closes #1655
2016-07-04 18:09:47 +09:00

2337 lines
97 KiB
C++

/*------------------------------------------------------------------------------------
this file is part of notepad++
Copyright (C)2003 Don HO < donho@altern.org >
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
----------------------------------------------------------------------------------------*/
#include <string>
#include <map>
#include <vector>
#include <assert.h>
#include <windows.h>
#include "Platform.h"
#include "ILexer.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "WordList.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "LexerModule.h"
#include "PropSetSimple.h"
#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif
#define CL_CURRENT 0x1
#define CL_PREV 0x2
#define CL_PREVPREV 0x4
#define FOLD_NONE 0
#define FOLD_OPEN 1
#define FOLD_MIDDLE 2
#define FOLD_CLOSE 3
#define COMMENTLINE_NO 0
#define COMMENTLINE_YES 1
#define COMMENTLINE_SKIP_TESTING 2
#define SEPARATOR_DOT 0
#define SEPARATOR_COMMA 1
#define SEPARATOR_BOTH 2
#define NI_OPEN 0
#define NI_CLOSE 1
#define NO_DELIMITER 0
#define FORWARD_WHITESPACE_FOUND 1
#define FORWARD_KEYWORD_FOUND 2
#define SC_ISCOMMENTLINE 0x8000
#define MULTI_PART_LIMIT 100
#define PURE_LC_NONE 0 // must be in synch with the same values in PowerEditor/src/Parameters.h
#define PURE_LC_BOL 1
#define PURE_LC_WSP 2
#define EOL_DEFAULT_VALUE 0
#define EOL_SKIP_CHECK 1
#define EOL_FORCE_CHECK 2
#define MAPPER_TOTAL 15
#define FW_VECTORS_TOTAL SCE_USER_TOTAL_DELIMITERS + 9
const int maskMapper[MAPPER_TOTAL] =
{
SCE_USER_MASK_NESTING_OPERATORS2,
SCE_USER_MASK_NESTING_FOLDERS_IN_CODE2_OPEN,
SCE_USER_MASK_NESTING_FOLDERS_IN_CODE2_MIDDLE,
SCE_USER_MASK_NESTING_FOLDERS_IN_CODE2_CLOSE,
SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_OPEN,
SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_MIDDLE,
SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_CLOSE,
SCE_USER_MASK_NESTING_KEYWORD1,
SCE_USER_MASK_NESTING_KEYWORD2,
SCE_USER_MASK_NESTING_KEYWORD3,
SCE_USER_MASK_NESTING_KEYWORD4,
SCE_USER_MASK_NESTING_KEYWORD5,
SCE_USER_MASK_NESTING_KEYWORD6,
SCE_USER_MASK_NESTING_KEYWORD7,
SCE_USER_MASK_NESTING_KEYWORD8
};
const int styleMapper[MAPPER_TOTAL] =
{
SCE_USER_STYLE_OPERATOR,
SCE_USER_STYLE_FOLDER_IN_CODE2,
SCE_USER_STYLE_FOLDER_IN_CODE2,
SCE_USER_STYLE_FOLDER_IN_CODE2,
SCE_USER_STYLE_FOLDER_IN_COMMENT,
SCE_USER_STYLE_FOLDER_IN_COMMENT,
SCE_USER_STYLE_FOLDER_IN_COMMENT,
SCE_USER_STYLE_KEYWORD1,
SCE_USER_STYLE_KEYWORD2,
SCE_USER_STYLE_KEYWORD3,
SCE_USER_STYLE_KEYWORD4,
SCE_USER_STYLE_KEYWORD5,
SCE_USER_STYLE_KEYWORD6,
SCE_USER_STYLE_KEYWORD7,
SCE_USER_STYLE_KEYWORD8
};
const int foldingtMapper[MAPPER_TOTAL] =
{
FOLD_NONE,
FOLD_OPEN,
FOLD_MIDDLE,
FOLD_CLOSE,
FOLD_OPEN,
FOLD_MIDDLE,
FOLD_CLOSE,
FOLD_NONE,
FOLD_NONE,
FOLD_NONE,
FOLD_NONE,
FOLD_NONE,
FOLD_NONE,
FOLD_NONE,
FOLD_NONE
};
using namespace std;
typedef vector<vector<string>> vvstring;
// static vector<int> * foldVectorStatic; // foldVectorStatic is used for debugging only, it should be commented out in production code !
struct forwardStruct
{
vvstring * vec;
int sceID;
int maskID;
forwardStruct(): vec(0), sceID(0), maskID(0) {}; // constructor, useless but obligatory
forwardStruct * Set (vvstring * vec, int sceID, int maskID) {
this->vec = vec;
this->sceID = sceID;
this->maskID = maskID;
return this;
}
}FWS; // just one instance
struct nestedInfo {
unsigned int position;
int nestedLevel;
int index;
int state;
int opener;
// constructor, useless but obligatory
nestedInfo():position(0), nestedLevel(0), index(0), state(0), opener(0) {};
nestedInfo * Set (unsigned int position, int nestedLevel, int index, int state, int opener) {
this->position = position;
this->nestedLevel = nestedLevel;
this->index = index;
this->state = state;
this->opener = opener;
return this;
}
};
static nestedInfo NI; // also just one instance
struct udlKeywordsMapStruct
{
vvstring commentLineOpen, commentLineContinue, commentLineClose;
vvstring commentOpen, commentClose;
vvstring delim1Open, delim1Escape, delim1Close;
vvstring delim2Open, delim2Escape, delim2Close;
vvstring delim3Open, delim3Escape, delim3Close;
vvstring delim4Open, delim4Escape, delim4Close;
vvstring delim5Open, delim5Escape, delim5Close;
vvstring delim6Open, delim6Escape, delim6Close;
vvstring delim7Open, delim7Escape, delim7Close;
vvstring delim8Open, delim8Escape, delim8Close;
vvstring operators1;
vvstring foldersInCode1Open, foldersInCode1Middle, foldersInCode1Close;
vvstring foldersInCode2Open, foldersInCode2Middle, foldersInCode2Close;
vector<string> prefixTokens1;
vector<string> prefixTokens2;
vector<string> suffixTokens1;
vector<string> suffixTokens2;
vector<string> extrasTokens1;
vector<string> extrasTokens2;
vector<string> rangeTokens;
vector<string> negativePrefixTokens1;
vector<string> negativePrefixTokens2;
vector<string> negativeExtrasTokens2;
};
// key value is of type "int" so it could receive pointer value !!
// UDL name is defined as "const char *" in UserLangContainer class
// so, map will use pointer value (not value pointed to!) as the key
typedef map<int, udlKeywordsMapStruct> udlMapType;
static udlMapType udlKeywordsMap;
// key value is of type "int" so it could receive pointer value !!
// currentBufferID is defined as "Buffer *" in ScintillaEditView class
// so, map will use pointer value (not value pointed to!) as the key
typedef map<int, vector<nestedInfo> > nestedMapType;
static nestedMapType nestedMap;
static inline bool isWhiteSpace(const int ch)
{
return (ch > 0 && ch < 0x21);
}
static inline bool isWhiteSpace2(unsigned char ch, int & nlCount, unsigned char excludeNewLine=0, unsigned char chNext=0)
{
// multi-part keywords come in two flavors:
// 1. "else if" (internally mapped to "else\vif") where '\v' can be replaced by spaces, tabs and new lines
// 2. 'else if" (internally mapped to "else\bif") where '\b' can be replaced by spaces, tabs but not new lines
// 'excludeNewLine' parameter is used to differentiate the two
if ((ch == '\n') || (ch == '\r' && chNext != '\n'))
++nlCount;
if (excludeNewLine == '\b')
return (ch == ' ') || (ch == '\t');
else
return isWhiteSpace(ch);
}
static bool isInListForward2(vvstring * fwEndVectors[], int totalVectors, StyleContext & sc, bool ignoreCase, int forward)
{
// forward check for multi-part keywords and numbers
// this is differnt from 'isInListForward' function because
// search for keyword is not performed at sc.currentPos but rather
// at some position forward of sc.currentPos
vvstring::iterator iter1;// = openVector.begin();
vector<string>::iterator iter2;
string::iterator iter3;
int index = 0;
int a = 0;
int b = 0;
for (int i=0; i<totalVectors; ++i)
{
if (fwEndVectors[i] && !fwEndVectors[i]->empty())
{
index = 0;
a = 0;
b = 0;
for (iter1 = fwEndVectors[i]->begin(); iter1 != fwEndVectors[i]->end(); ++iter1)
{
iter2 = iter1->begin();
for (; iter2 != iter1->end(); ++iter2)
{
iter3 = iter2->begin();
index = 0;
for (; ; ++iter3)
{
a = ignoreCase?toupper(*iter3):*iter3;
b = ignoreCase?toupper(sc.GetRelative(forward + index++)):sc.GetRelative(forward + index++);
if (a != b)
break;
if (iter3 != iter2->end())
return true;
}
}
}
}
}
return false;
}
static bool isInListForward3(vector<string> * tokens, StyleContext & sc, bool ignoreCase, int offset, int & moveForward)
{
// forward check for vector<string> keywords, with offset
moveForward = 0;
unsigned char a = 0;
unsigned char b = 0;
int indexb = 0;
bool isFound = false;
vector<string>::iterator iter1;
string::iterator iter2;
for (iter1 = tokens->begin(); iter1 != tokens->end(); ++iter1)
{
a = 0;
b = 0;
indexb = 0;
isFound = true;
for (iter2 = iter1->begin(); iter2 != iter1->end(); ++iter2)
{
a = static_cast<unsigned char>(ignoreCase?toupper(*iter2):*iter2);
b = static_cast<unsigned char>(ignoreCase?toupper(sc.GetRelative(offset + indexb++)):sc.GetRelative(offset + indexb++));
if (a != b)
{
isFound = false;
break;
}
}
if (isFound == true)
{
moveForward += iter1->length();
break;
}
}
return isFound;
}
static inline bool IsADigit(char ch)
{
return isascii(ch) && isdigit(ch);
}
static bool IsNumber(StyleContext & sc, vector<string> * numberTokens[], vvstring * fwEndVectors[],
bool ignoreCase, int decSeparator, int & moveForward )
{
moveForward = 0;
bool hasDot = false;
bool hasPrefix1 = false;
bool hasPrefix2 = false;
bool hasSuffix1 = false;
bool hasSuffix2 = false;
bool hasExtras2 = false;
bool hasRange = false;
bool hasExp = false;
bool previousWasRange = false;
int offset = 0;
vector<string> * prefixTokens1 = numberTokens[0];
vector<string> * prefixTokens2 = numberTokens[1];
vector<string> * extrasTokens1 = numberTokens[2];
vector<string> * extrasTokens2 = numberTokens[3];
vector<string> * suffixTokens1 = numberTokens[4];
vector<string> * suffixTokens2 = numberTokens[5];
vector<string> * rangeTokens = numberTokens[6];
vector<string> * negativePrefixTokens1 = numberTokens[7];
vector<string> * negativePrefixTokens2 = numberTokens[8];
vector<string> * negativeExtrasTokens2 = numberTokens[9];
// treat .1234 as correct number sequence
if (((decSeparator == SEPARATOR_BOTH || decSeparator == SEPARATOR_DOT) && sc.ch == '.') ||
((decSeparator == SEPARATOR_BOTH || decSeparator == SEPARATOR_COMMA) && sc.ch == ','))
{
if (IsADigit(sc.chNext))
{
hasDot = true;
offset = 2;
}
}
else
{
// or is it a prefixed number?
vector<string>::iterator iter = prefixTokens2->begin();
vector<string>::iterator last = prefixTokens2->end();
if (sc.ch == '-')
{
iter = negativePrefixTokens2->begin();
last = negativePrefixTokens2->end();
}
for (; iter != last; ++iter)
{
if (ignoreCase?sc.MatchIgnoreCase2(iter->c_str()) : sc.Match(iter->c_str()))
break;
}
if (iter != last)
{
// prefix2 is styled as number only if followed by an actual number or NBR_EXTRA_CHAR
int skipForward = 0;
if (isInListForward3(extrasTokens1, sc, ignoreCase, iter->length(), skipForward))
{
offset += iter->length() + skipForward;
hasPrefix2 = true;
hasExp = true; // can't be a scientific E notation
}
else if (IsADigit(sc.GetRelative(iter->length())))
{
offset += iter->length() + 1;
hasPrefix2 = true;
hasExp = true; // can't be a scientific E notation
}
}
if (hasPrefix2 == false)
{
// or is it a prefixed1 number?
vector<string>::iterator iter = prefixTokens1->begin();
vector<string>::iterator last = prefixTokens1->end();
if (sc.ch == '-')
{
iter = negativePrefixTokens1->begin();
last = negativePrefixTokens1->end();
}
for (; iter != last; ++iter)
{
if (ignoreCase?sc.MatchIgnoreCase2(iter->c_str()) : sc.Match(iter->c_str()))
break;
}
if (iter != last)
{
// prefix1 is styled as number only if followed by an actual number (decimal digit)
if (IsADigit(sc.GetRelative(iter->length())))
{
offset += iter->length() + 1;
hasPrefix1 = true;
hasPrefix2 = false; // can't have any EXTRA_CHARs
hasExp = true; // can't be a scientific E notation
}
}
}
if (hasPrefix1 == false && hasPrefix2 == false)
{
// or is it a suffixed1 number with extras2?
vector<string>::iterator iter = extrasTokens2->begin();
vector<string>::iterator last = extrasTokens2->end();
if (sc.ch == '-')
{
iter = negativeExtrasTokens2->begin();
last = negativeExtrasTokens2->end();
}
for (; iter != last; ++iter)
{
if (ignoreCase?sc.MatchIgnoreCase2(iter->c_str()) : sc.Match(iter->c_str()))
break;
}
if (iter != last)
{
offset += iter->length();
hasExtras2 = true;
hasExp = true; // can't be a scientific E notation
}
}
}
// is it a simple digit?
if (offset == 0)
{
if (IsADigit(sc.ch))
{
offset = 1;
}
// or prefixed simple digit?
else if ((sc.ch == '-' || sc.ch == '+') && IsADigit(sc.chNext) && !IsADigit(sc.chPrev))
{
offset = 2;
}
if (offset == 0)
return false;
}
int skipForward = 0;
for (;;)
{
skipForward = 0;
// if (isInListForward2(fwEndVectors, (*fwEndVectors)->size(), sc, ignoreCase, offset) || isWhiteSpace(sc.GetRelative(offset)))
if (isWhiteSpace(sc.GetRelative(offset)) || isInListForward2(fwEndVectors, 12, sc, ignoreCase, offset))
{
if (hasExtras2 == true && hasSuffix1 == false)
return false;
moveForward = offset;
return true; // yay, finally we have a number
}
if (hasRange == false)
{
if (isInListForward3(rangeTokens, sc, ignoreCase, offset, skipForward))
{
if (hasExtras2 == true && hasSuffix1 == false)
return false;
offset += skipForward;
hasSuffix1 = false;
hasSuffix2 = false;
hasDot = false;
hasRange = true;
hasExp = false;
hasExtras2 = false;
previousWasRange = true;
continue;
}
}
if (hasSuffix2 == true) // only RANGE_CHARs are allowed after SUFFIX_CHARs
return false;
if (hasPrefix2 == true)
{
if (isInListForward3(extrasTokens1, sc, ignoreCase, offset, skipForward))
{
offset += skipForward;
continue;
}
}
if (hasSuffix1 == false && hasPrefix1 == false && hasPrefix2 == false)
{
if (isInListForward3(suffixTokens1, sc, ignoreCase, offset, skipForward))
{
offset += skipForward;
hasExtras2 = false;
hasSuffix1 = true;
continue;
}
if (isInListForward3(extrasTokens2, sc, ignoreCase, offset, skipForward))
{
offset += skipForward;
hasExtras2 = true;
hasExp = true; // can't be a scientific E notation
continue;
}
}
if (hasSuffix2 == false)
{
if (isInListForward3(suffixTokens2, sc, ignoreCase, offset, skipForward))
{
offset += skipForward;
hasSuffix2 = true;
continue;
}
}
if (previousWasRange == true) // prefix in the middle is an error case, so any number is treated as if it had a prefix
{ // the only acceptable position for prefix is immediatelly after range char, e.g. 0x10--0x15
if (isInListForward3(prefixTokens2, sc, ignoreCase, offset, skipForward))
{
offset += skipForward;
hasExp = false;
hasPrefix2 = true;
continue;
}
if (isInListForward3(prefixTokens1, sc, ignoreCase, offset, skipForward))
{
offset += skipForward;
hasExp = false;
hasPrefix1 = true;
continue;
}
}
if (IsADigit(sc.GetRelative(offset)))
{
offset += 1;
continue;
}
if (hasDot == false)
{
// treat .1234 (or ,1234) as correct number sequence
if (((decSeparator == SEPARATOR_BOTH || decSeparator == SEPARATOR_DOT) &&
(sc.GetRelative(offset) == '.'))
||
((decSeparator == SEPARATOR_BOTH || decSeparator == SEPARATOR_COMMA) &&
(sc.GetRelative(offset) == ',')))
{
if (IsADigit(sc.GetRelative(offset + 1)))
{
if (IsADigit(sc.GetRelative(offset - 1)) || previousWasRange == true)
{
offset += 2;
hasDot = true;
continue;
}
}
}
}
if (hasExp == false)
{
if (toupper(sc.GetRelative(offset)) == 'E') // treat E as scientific notation only if it does not match extra chars!!
{
unsigned char chPrev = sc.GetRelative(offset - 1);
unsigned char chNext = sc.GetRelative(offset + 1);
unsigned char chNextNext = sc.GetRelative(offset + 2);
if (IsADigit(chPrev))
{
int move = 0;
if (IsADigit(chNext))
{
move = 1;
}
else if ((chNext == '+' || chNext == '-') && IsADigit(chNextNext))
{
move = 2;
}
if (move > 0)
{
offset += move;
hasPrefix2 = false; // EXTRA_CHARs are not allowed in E notation
hasDot = false;
hasExp = true;
continue;
}
}
}
}
// not a number
return false;
}
}
static inline void SubGroup(const char * s, vvstring & vec, bool group=false)
{
unsigned int length = strlen(s);
char * temp = new char[length+1];
unsigned int index = 0;
vector<string> subvector;
unsigned int i = 0;
for (unsigned int j=0; j<length+1; ++j)
temp[j] = 0;
if (length >= 2 && s[0] == '(' && s[1] == '(')
{
i = 2;
group = true;
}
if (length >= 2 && s[length - 1] == ')' && s[length - 2] == ')')
length -= 2;
if (!group && *s)
{
subvector.push_back(s);
}
else
{
for (; i<length; ++i)
{
if (s[i] == ' ')
{
if (*temp)
{
if (!strcmp(temp, "EOL"))
{
subvector.push_back("\r\n");
subvector.push_back("\n");
subvector.push_back("\r");
}
else
subvector.push_back(temp);
index = 0;
for (unsigned int j=0; j<length; ++j)
temp[j] = 0;
}
}
else if (i == length-1)
{
temp[index++] = s[i];
if (*temp)
{
if (!strcmp(temp, "EOL"))
{
subvector.push_back("\r\n");
subvector.push_back("\n");
subvector.push_back("\r");
}
else
subvector.push_back(temp);
}
}
else
{
temp[index++] = s[i];
}
}
}
if (!subvector.empty())
vec.push_back(subvector);
delete [] temp;
}
static inline void GenerateVector(vvstring & vec, const char * s, char * prefix, int minLength)
{
unsigned int length = strlen(s);
char * temp = new char[length];
unsigned int index = 0;
bool copy = false;
bool inGroup = false;
for (unsigned int j=0; j<length; ++j)
temp[j] = 0;
vec.clear();
for (unsigned int i=0; i<length; ++i)
{
if (copy && !inGroup && s[i] == ' ')
{
SubGroup(temp, vec, inGroup);
index = 0;
copy = false;
for (unsigned int j=0; j<length; ++j)
temp[j] = 0;
}
if ( (s[i] == ' ' && s[i+1] == prefix[0] && s[i+2] == prefix[1] && s[i+3] != ' ') ||
( i == 0 && s[0] == prefix[0] && s[1] == prefix[1] && s[i+2] != ' ') )
{
if (i > 0) i += 1; // skip space
i += 2; // skip prefix
copy = true;
if (s[i] == ' ')
continue;
if (s[i] == '(' && s[i+1] == '(')
inGroup = true;
}
if (inGroup && s[i] == ')' && s[i+1] == ')')
inGroup = false;
if (copy)
temp[index++] = s[i];
}
if (length)
SubGroup(temp, vec, inGroup);
vector<string> emptyVector;
for (int i = vec.size(); i < minLength; ++i)
{
vec.push_back(emptyVector);
}
delete [] temp;
}
static inline void StringToVector(char * original, vector<string> & tokenVector, bool negative=false)
{
// this is rarely used, so I chose std::string for simplicity reasons
// for better performance C-strings could be used
string temp = "";
char * pch = original;
while (*pch != NULL)
{
if (*pch != ' ')
temp += *pch; //
else if (temp.size() > 0)
{
if (negative)
tokenVector.push_back("-" + temp);
else
tokenVector.push_back(temp);
temp = "";
}
++pch;
}
if (temp.size() > 0)
{
if (negative)
tokenVector.push_back("-" + temp);
else
tokenVector.push_back(temp);
}
}
static inline void ReColoringCheck(unsigned int & startPos, unsigned int & nestedLevel, int & initStyle, int & openIndex,
int & isCommentLine, bool & isInComment, Accessor & styler, vector<nestedInfo> & lastNestedGroup,
vector<nestedInfo> & nestedVector, /* vector<int> & foldVector, */ int & continueCommentBlock)
{
// re-coloring always starts at line beginning !!
// special exception for multipart keywords
initStyle = styler.StyleAt(startPos-1); // check style of previous new line character
if ( (initStyle >= SCE_USER_STYLE_KEYWORD1 && initStyle < (SCE_USER_STYLE_KEYWORD1+SCE_USER_TOTAL_KEYWORD_GROUPS)) // keywords1-8
|| initStyle == SCE_USER_STYLE_FOLDER_IN_COMMENT
|| initStyle == SCE_USER_STYLE_FOLDER_IN_CODE2 )
{
// we are in middle of multi-part keyword that contains newline characters, go back until current style ends
while (startPos >= 0 && styler.StyleAt(--startPos) == initStyle);
}
if (static_cast<int>(startPos) < 0)
startPos = 0;
if (startPos > 0)
{
// go back until first EOL char
char ch = 0;
do
{
ch = styler.SafeGetCharAt(--startPos);
if (startPos == -1)
startPos = 0;
}
while(ch != '\r' && ch != '\n' && startPos > 0);
if (startPos > 0)
startPos += 1; // compensate for decrement operation
}
if (startPos == 0)
{
// foldVector.clear();
nestedVector.clear();
lastNestedGroup.clear();
initStyle = SCE_USER_STYLE_IDENTIFIER;
return;
}
// clear all data on positions forward of 'startPos' as we
// are about to re-color that part of the document.
vector<nestedInfo>::iterator iter = nestedVector.begin();
for (; iter != nestedVector.end(); ++iter)
{
if (iter->position >= startPos)
{
nestedVector.erase(iter, nestedVector.end());
break;
}
}
if (!nestedVector.empty())
{
// go back to last nesting level '1' (or beginning of vector if no level '1' is found)
iter = --nestedVector.end();
lastNestedGroup.clear();
while (iter->nestedLevel > 1 && iter != nestedVector.begin())
--iter;
}
else
{
iter = nestedVector.end();
}
// recreate lastNestedGroup, skip adjecent OPEN/CLOSE pairs
// nesting group is something like:
// "first delimiter 'nested delimiter 1 /*nested delimiter 2*/ delimiter 1 again' first delimiter again"
// if user is editing somewhere inside this group, than 'lastNestedGroup' provides info about nesting
// this is much more convinient that trying to obtain the same info from 'nestedVector'
vector<nestedInfo>::iterator last;
while (iter != nestedVector.end())
{
if (iter->opener == NI_OPEN)
lastNestedGroup.push_back(*iter);
else if (iter->opener == NI_CLOSE && !lastNestedGroup.empty())
{
last = --lastNestedGroup.end();
if (last->opener == NI_OPEN)
if (last->nestedLevel == iter->nestedLevel)
if (last->state == iter->state)
if (last->index == iter->index)
lastNestedGroup.erase(last);
}
++iter;
}
if (!lastNestedGroup.empty())
{
last = --lastNestedGroup.end();
initStyle = last->state;
openIndex = last->index;
nestedLevel = last->nestedLevel;
// are we nested somewhere in comment?
for (; ; --last)
{
if (last->state == SCE_USER_STYLE_COMMENT)
{
isInComment = true;
isCommentLine = COMMENTLINE_YES;
}
if (last->state == SCE_USER_STYLE_COMMENTLINE)
{
isCommentLine = COMMENTLINE_YES;
}
if (last == lastNestedGroup.begin())
break;
}
}
else
{
initStyle = SCE_USER_STYLE_IDENTIFIER;
openIndex = -1;
nestedLevel = 0;
}
// are we in fold block of comment lines?
int lineCurrent = styler.GetLine(startPos);
if ((styler.LevelAt(lineCurrent) & SC_ISCOMMENTLINE) != 0)
continueCommentBlock |= CL_CURRENT;
if (lineCurrent >= 1)
if ((styler.LevelAt(lineCurrent - 1) & SC_ISCOMMENTLINE) != 0)
continueCommentBlock |= CL_PREV;
if (lineCurrent >= 2)
if ((styler.LevelAt(lineCurrent - 2) & SC_ISCOMMENTLINE) != 0)
if (continueCommentBlock & CL_PREV)
continueCommentBlock |= CL_PREVPREV;
// foldVector.erase(foldVector.begin() + lineCurrent, foldVector.end());
}
static bool isInListForward(vvstring & openVector, StyleContext & sc, bool ignoreCase, int & openIndex, int & skipForward)
{
// forward check for standard (sigle part) keywords
skipForward = 0;
vector<vector<string>>::iterator iter1 = openVector.begin();
vector<string>::iterator iter2;
for (; iter1 != openVector.end(); ++iter1)
{
iter2 = iter1->begin();
for (; iter2 != iter1->end(); ++iter2)
{
if (ignoreCase?sc.MatchIgnoreCase2(iter2->c_str()):sc.Match(iter2->c_str()))
{
openIndex = iter1 - openVector.begin();
skipForward = iter2->length();
return true;
}
}
}
return false;
}
static bool isInListBackward(WordList & list, StyleContext & sc, bool specialMode, bool ignoreCase,
int & moveForward, vvstring * fwEndVectors[], int & nlCount, unsigned int docLength)
{
// backward search
// this function compares last identified 'word' (text surrounded by spaces or other forward keywords)
// with all keywords within 'WordList' object
// 'isInListBackward' can search for multi-part keywords too. Such keywords have variable length,
// in case 'isInListBackward' finds such keywords it will set 'moveForward' parameter so algorythm could adjust position
if (!list.Length())
return false;
moveForward = 0;
int offset = -1 * sc.LengthCurrent(); // length of 'word' that needs to be investigated
unsigned char a = 0; // iterator for user defined keywords
unsigned char b = 0; // iterator for text in the file
unsigned char bNext = 0;
unsigned char wsChar = 0;
unsigned char firstChar = sc.GetRelative(offset);
int fwDelimiterFound = NO_DELIMITER;
int nlCountTemp = 0;
int indexa = 0;
int indexb = 0;
int i = list.StartAt(firstChar);
bool doUpperLoop = ignoreCase;
if (ignoreCase)
{
i = list.StartAt(tolower(firstChar));
if (i == -1)
{
i = list.StartAt(toupper(firstChar));
if (i == -1)
return false;
doUpperLoop = false;
}
}
while (i >= 0)
{
while (static_cast<unsigned char>(ignoreCase?toupper(list.WordAt(i)[0]):list.WordAt(i)[0]) == (ignoreCase?toupper(firstChar):firstChar))
{
a = 0;
b = 0;
bNext = 0;
indexa = 0;
indexb = 0;
wsChar = 0;
fwDelimiterFound = NO_DELIMITER;
do
{
a = static_cast<unsigned char>(ignoreCase?toupper(list.WordAt(i)[indexa++]):list.WordAt(i)[indexa++]);
if (a == '\v' || a == '\b')
{
wsChar = a;
b = sc.GetRelative(offset + indexb++);
bNext = sc.GetRelative(offset + indexb);
if (isWhiteSpace2(b, nlCountTemp, wsChar, bNext))
{
do {
b = sc.GetRelative(offset + indexb++);
bNext = sc.GetRelative(offset + indexb);
}
while((sc.currentPos + offset + indexb) <= docLength && isWhiteSpace2(b, nlCountTemp, wsChar, bNext));
a = static_cast<unsigned char>(ignoreCase?toupper(list.WordAt(i)[indexa++]):list.WordAt(i)[indexa++]);
}
b = ignoreCase?toupper(b):b;
}
else
b = ignoreCase?toupper(sc.GetRelative(offset + indexb++)):sc.GetRelative(offset + indexb++);
}
while (a && (a == b));
if (!a)
{
--indexb; // decrement indexb to compensate for comparing with '\0' in previous loop
if (wsChar)
{
// multi-part keyword is found,
// but it must be followed by whitespace (or 'forward' keyword)
// otherwise "else if" might wrongly match "else iff"
bNext = sc.GetRelative(indexb + offset);
if (isWhiteSpace(bNext))
fwDelimiterFound = FORWARD_WHITESPACE_FOUND;
if (fwDelimiterFound == NO_DELIMITER)
{
if (isInListForward2(fwEndVectors, FW_VECTORS_TOTAL, sc, ignoreCase, indexb + offset))
{
fwDelimiterFound = FORWARD_KEYWORD_FOUND;
}
}
// special case when multi-part keywords have 'prefix' option enabled
// then the next word in the text file must be treated as part of multi-part keyword
// e.g. prefixed "else if" matches "else if nextWord", but not "else iffy"
if (specialMode)
{
if (fwDelimiterFound == FORWARD_WHITESPACE_FOUND) // there must be a white space !!
{
// skip whitespace (all of it)
int savedPosition = indexb; // return here if whitespace is not followed by another word
for (;;)
{
if ((sc.currentPos + offset + indexb) > docLength)
break;
if (!isWhiteSpace2(sc.GetRelative(offset + indexb), nlCountTemp, wsChar, sc.GetRelative(offset + indexb + 1)))
break;
++indexb;
}
// skip next "word" (if next word is not found, go back to end of multi-part keyword)
// it is not necessary to check EOF position here, because sc.GetRelative returns ' ' beyond EOF
bool nextWordFound = false;
while (!isWhiteSpace2(sc.GetRelative(indexb + offset), nlCountTemp, wsChar, sc.GetRelative(offset + indexb + 1)))
{
if (isInListForward2(fwEndVectors, FW_VECTORS_TOTAL, sc, ignoreCase, indexb + offset))
{
break;
}
++indexb;
nextWordFound = true;
}
if (nextWordFound == false)
indexb = savedPosition;
}
}
}
// keyword is read fully, decide if we can leave this function
nlCount += nlCountTemp;
moveForward = indexb + offset; // offset is already negative
if (wsChar)
{
if (fwDelimiterFound != NO_DELIMITER)
return true; // multi part keyword found
}
else if (moveForward == 0)
return true; // single part keyword found
else if (specialMode)
return true; // prefixed single part keyword found
}
nlCountTemp = 0;
++i;
}
// run one more time for capital letter version
if (doUpperLoop)
{
i = list.StartAt(toupper(firstChar));
doUpperLoop = false;
}
else
break;
}
return false;
}
static void setBackwards(WordList * kwLists[], StyleContext & sc, bool prefixes[], bool ignoreCase,
int nestedKey, vvstring * fwEndVectors[], int & levelMinCurrent,
int & levelNext, int & nlCount, bool & dontMove, unsigned int docLength)
{
if (sc.LengthCurrent() == 0)
return;
int folding = FOLD_NONE;
int moveForward = 0;
for (int i=0; i<MAPPER_TOTAL; ++i)
{
if (nestedKey & maskMapper[i])
{
if (isInListBackward(*kwLists[i], sc, prefixes[i], ignoreCase, moveForward, fwEndVectors, nlCount, docLength))
{
folding = foldingtMapper[i];
if (moveForward > 0)
{
sc.Forward(moveForward);
dontMove = true;
}
sc.ChangeState(styleMapper[i]);
break;
}
}
}
if (folding == FOLD_MIDDLE)
{
// treat middle point as a sequence of: FOLD_CLOSE followed by FOLD_OPEN
levelNext--;
folding = FOLD_OPEN;
}
if (folding == FOLD_OPEN)
{
if (levelMinCurrent > levelNext)
levelMinCurrent = levelNext;
levelNext++;
}
else if (folding == FOLD_CLOSE)
{
levelNext--;
}
}
static bool isInListNested(int nestedKey, vector<forwardStruct> & forwards, StyleContext & sc,
bool ignoreCase, int & openIndex, int & skipForward, int & newState, int pureLC,
bool visibleChars, vector<string> * numberTokens[], vvstring ** numberDelims, int decSeparator)
{
// check if some other delimiter is nested within current delimiter
// all delimiters are freely checked but line comments must be synched with property 'pureLC'
int backup = openIndex;
vector<forwardStruct>::iterator iter = forwards.begin();
for (; iter != forwards.end(); ++iter)
{
if (nestedKey & iter->maskID)
{
if ((iter->maskID != SCE_USER_MASK_NESTING_COMMENT_LINE) ||
(iter->maskID == SCE_USER_MASK_NESTING_COMMENT_LINE &&
((pureLC == PURE_LC_NONE) ||
(pureLC == PURE_LC_BOL && (sc.chPrev == '\r' || sc.chPrev == '\n')) ||
(pureLC == PURE_LC_WSP && visibleChars == false))))
{
if (isInListForward(*(iter->vec), sc, ignoreCase, openIndex, skipForward))
{
newState = iter->sceID;
return true;
}
}
}
}
if (nestedKey & SCE_USER_MASK_NESTING_NUMBERS)
{
if (IsNumber(sc, numberTokens, numberDelims, ignoreCase, decSeparator, skipForward))
{
newState = SCE_USER_STYLE_NUMBER;
return true;
}
}
openIndex = backup;
return false;
}
static void readLastNested(vector<nestedInfo> & lastNestedGroup, int & newState, int & openIndex)
{
// after delimiter ends we need to determine whether we are entering some other delimiter (in case of nesting)
// or do we simply start over from default style.
newState = SCE_USER_STYLE_IDENTIFIER;
openIndex = -1;
if (!lastNestedGroup.empty())
{
lastNestedGroup.erase(lastNestedGroup.end()-1);
if (!lastNestedGroup.empty())
{
newState = (--lastNestedGroup.end())->state;
openIndex = (--lastNestedGroup.end())->index;
}
}
}
static void ColouriseUserDoc(unsigned int startPos, int length, int initStyle, WordList *kwLists[], Accessor &styler)
{
bool foldComments = styler.GetPropertyInt("userDefine.allowFoldOfComments", 0) != 0;
bool ignoreCase = styler.GetPropertyInt("userDefine.isCaseIgnored", 0) != 0;
bool foldCompact = styler.GetPropertyInt("userDefine.foldCompact", 0) != 0;
int pureLC = styler.GetPropertyInt("userDefine.forcePureLC", 0);
bool prefixes[MAPPER_TOTAL];
for (int i=0; i<MAPPER_TOTAL; ++i) // only KEYWORDS1-8 can be prefixed
prefixes[i] = false;
// positions are hardcoded and they must be in synch with positions in "styleMapper" array!!
prefixes[7] = styler.GetPropertyInt("userDefine.prefixKeywords1", 0) != 0;
prefixes[8] = styler.GetPropertyInt("userDefine.prefixKeywords2", 0) != 0;
prefixes[9] = styler.GetPropertyInt("userDefine.prefixKeywords3", 0) != 0;
prefixes[10] = styler.GetPropertyInt("userDefine.prefixKeywords4", 0) != 0;
prefixes[11] = styler.GetPropertyInt("userDefine.prefixKeywords5", 0) != 0;
prefixes[12] = styler.GetPropertyInt("userDefine.prefixKeywords6", 0) != 0;
prefixes[13] = styler.GetPropertyInt("userDefine.prefixKeywords7", 0) != 0;
prefixes[14] = styler.GetPropertyInt("userDefine.prefixKeywords8", 0) != 0;
char nestingBuffer[] = "userDefine.nesting.00"; // "00" is only a placeholder, the actual number is set by _itoa
_itoa(SCE_USER_STYLE_COMMENT, (nestingBuffer+20), 10); int commentNesting = styler.GetPropertyInt(nestingBuffer, 0);
_itoa(SCE_USER_STYLE_COMMENTLINE, (nestingBuffer+20), 10); int lineCommentNesting = styler.GetPropertyInt(nestingBuffer, 0);
_itoa(SCE_USER_STYLE_DELIMITER1, (nestingBuffer+19), 10); int delim1Nesting = styler.GetPropertyInt(nestingBuffer, 0); // one byte difference
_itoa(SCE_USER_STYLE_DELIMITER2, (nestingBuffer+19), 10); int delim2Nesting = styler.GetPropertyInt(nestingBuffer, 0); // for two-digit numbers
_itoa(SCE_USER_STYLE_DELIMITER3, (nestingBuffer+19), 10); int delim3Nesting = styler.GetPropertyInt(nestingBuffer, 0);
_itoa(SCE_USER_STYLE_DELIMITER4, (nestingBuffer+19), 10); int delim4Nesting = styler.GetPropertyInt(nestingBuffer, 0);
_itoa(SCE_USER_STYLE_DELIMITER5, (nestingBuffer+19), 10); int delim5Nesting = styler.GetPropertyInt(nestingBuffer, 0);
_itoa(SCE_USER_STYLE_DELIMITER6, (nestingBuffer+19), 10); int delim6Nesting = styler.GetPropertyInt(nestingBuffer, 0);
_itoa(SCE_USER_STYLE_DELIMITER7, (nestingBuffer+19), 10); int delim7Nesting = styler.GetPropertyInt(nestingBuffer, 0);
_itoa(SCE_USER_STYLE_DELIMITER8, (nestingBuffer+19), 10); int delim8Nesting = styler.GetPropertyInt(nestingBuffer, 0);
commentNesting |= SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_OPEN
| SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_MIDDLE
| SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_CLOSE;
lineCommentNesting |= SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_OPEN
| SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_MIDDLE
| SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_CLOSE;
const int bwNesting = SCE_USER_MASK_NESTING_KEYWORD1
| SCE_USER_MASK_NESTING_KEYWORD2
| SCE_USER_MASK_NESTING_KEYWORD3
| SCE_USER_MASK_NESTING_KEYWORD4
| SCE_USER_MASK_NESTING_KEYWORD5
| SCE_USER_MASK_NESTING_KEYWORD6
| SCE_USER_MASK_NESTING_KEYWORD7
| SCE_USER_MASK_NESTING_KEYWORD8
| SCE_USER_MASK_NESTING_OPERATORS2
| SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_OPEN
| SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_MIDDLE
| SCE_USER_MASK_NESTING_FOLDERS_IN_COMMENT_CLOSE
| SCE_USER_MASK_NESTING_FOLDERS_IN_CODE2_OPEN
| SCE_USER_MASK_NESTING_FOLDERS_IN_CODE2_MIDDLE
| SCE_USER_MASK_NESTING_FOLDERS_IN_CODE2_CLOSE;
// creation of vvstring (short for vector<vector<string>>) objects is expensive,
// therefore these objects are created only at beginning of file, and saved to
// global std::map objects udlKeywordsMap and nestedMap
int currentBufferID = styler.GetPropertyInt("userDefine.currentBufferID", 0);
if (nestedMap.find(currentBufferID) == nestedMap.end())
{
nestedMap[currentBufferID] = vector<nestedInfo>();
}
vector<nestedInfo> & nestedVector = nestedMap[currentBufferID];
int sUdlName = styler.GetPropertyInt("userDefine.udlName", 0);
if (udlKeywordsMap.find(sUdlName) == udlKeywordsMap.end())
{
udlKeywordsMap[sUdlName] = udlKeywordsMapStruct();
}
vvstring & commentLineOpen = udlKeywordsMap[sUdlName].commentLineOpen;
vvstring & commentLineContinue = udlKeywordsMap[sUdlName].commentLineContinue;
vvstring & commentLineClose = udlKeywordsMap[sUdlName].commentLineClose;
vvstring & commentOpen = udlKeywordsMap[sUdlName].commentOpen;
vvstring & commentClose = udlKeywordsMap[sUdlName].commentClose;
vvstring & delim1Open = udlKeywordsMap[sUdlName].delim1Open;
vvstring & delim1Escape = udlKeywordsMap[sUdlName].delim1Escape;
vvstring & delim1Close = udlKeywordsMap[sUdlName].delim1Close;
vvstring & delim2Open = udlKeywordsMap[sUdlName].delim2Open;
vvstring & delim2Escape = udlKeywordsMap[sUdlName].delim2Escape;
vvstring & delim2Close = udlKeywordsMap[sUdlName].delim2Close;
vvstring & delim3Open = udlKeywordsMap[sUdlName].delim3Open;
vvstring & delim3Escape = udlKeywordsMap[sUdlName].delim3Escape;
vvstring & delim3Close = udlKeywordsMap[sUdlName].delim3Close;
vvstring & delim4Open = udlKeywordsMap[sUdlName].delim4Open;
vvstring & delim4Escape = udlKeywordsMap[sUdlName].delim4Escape;
vvstring & delim4Close = udlKeywordsMap[sUdlName].delim4Close;
vvstring & delim5Open = udlKeywordsMap[sUdlName].delim5Open;
vvstring & delim5Escape = udlKeywordsMap[sUdlName].delim5Escape;
vvstring & delim5Close = udlKeywordsMap[sUdlName].delim5Close;
vvstring & delim6Open = udlKeywordsMap[sUdlName].delim6Open;
vvstring & delim6Escape = udlKeywordsMap[sUdlName].delim6Escape;
vvstring & delim6Close = udlKeywordsMap[sUdlName].delim6Close;
vvstring & delim7Open = udlKeywordsMap[sUdlName].delim7Open;
vvstring & delim7Escape = udlKeywordsMap[sUdlName].delim7Escape;
vvstring & delim7Close = udlKeywordsMap[sUdlName].delim7Close;
vvstring & delim8Open = udlKeywordsMap[sUdlName].delim8Open;
vvstring & delim8Escape = udlKeywordsMap[sUdlName].delim8Escape;
vvstring & delim8Close = udlKeywordsMap[sUdlName].delim8Close;
vvstring & operators1 = udlKeywordsMap[sUdlName].operators1;
vvstring & foldersInCode1Open = udlKeywordsMap[sUdlName].foldersInCode1Open;
vvstring & foldersInCode1Middle = udlKeywordsMap[sUdlName].foldersInCode1Middle;
vvstring & foldersInCode1Close = udlKeywordsMap[sUdlName].foldersInCode1Close;
vector<string> & prefixTokens1 = udlKeywordsMap[sUdlName].prefixTokens1;
vector<string> & prefixTokens2 = udlKeywordsMap[sUdlName].prefixTokens2;
vector<string> & extrasTokens1 = udlKeywordsMap[sUdlName].extrasTokens1;
vector<string> & extrasTokens2 = udlKeywordsMap[sUdlName].extrasTokens2;
vector<string> & suffixTokens1 = udlKeywordsMap[sUdlName].suffixTokens1;
vector<string> & suffixTokens2 = udlKeywordsMap[sUdlName].suffixTokens2;
vector<string> & rangeTokens = udlKeywordsMap[sUdlName].rangeTokens;
vector<string> & negativePrefixTokens1 = udlKeywordsMap[sUdlName].negativePrefixTokens1;
vector<string> & negativePrefixTokens2 = udlKeywordsMap[sUdlName].negativePrefixTokens2;
vector<string> & negativeExtrasTokens2 = udlKeywordsMap[sUdlName].negativeExtrasTokens2;
if (startPos == 0)
{
// in keyword list objects, put longer multi-part string first,
// e.g. "else if" should go in front of "else"
bool equal = true;
bool isMultiPart = false;
bool switchPerformed = true;
while (switchPerformed)
{
switchPerformed = false;
for (int i=0; i<MAPPER_TOTAL; ++i) // for each keyword list object
{
for (int j=0; j<kwLists[i]->Length(); ++j) // for each keyword within object
{
equal = true;
int z = 0;
for (; kwLists[i]->WordAt(j)[z]; ++z) // for each letter within keyword
{
if (kwLists[i]->WordAt(j+1)[z] == '\v' || kwLists[i]->WordAt(j+1)[z] == '\b')
isMultiPart = true;
if (kwLists[i]->WordAt(j)[z] != kwLists[i]->WordAt(j+1)[z])
{
equal = false;
break;
}
}
if (!isMultiPart) // is next word multi part keyword?
{
for (int k=0; kwLists[i]->WordAt(j+1)[k]; ++k)
{
if (kwLists[i]->WordAt(j+1)[k] == '\v' || kwLists[i]->WordAt(j+1)[k] == '\b')
{
isMultiPart = true;
break;
}
}
}
if (equal && isMultiPart && kwLists[i]->WordAt(j+1)[z]) // perform switch only if next word is longer !
{
const char * temp = kwLists[i]->WordAt(j);
kwLists[i]->SetWordAt(j, kwLists[i]->WordAt(j+1));
kwLists[i]->SetWordAt(j+1, temp);
switchPerformed = true;
}
}
}
}
// if this is BOF, re-generate stuff in global map objects (udlKeywordsMap and nestedMap)
const char * sFoldersInCode1Open = styler.pprops->Get("userDefine.foldersInCode1Open");
const char * sFoldersInCode1Middle = styler.pprops->Get("userDefine.foldersInCode1Middle");
const char * sFoldersInCode1Close = styler.pprops->Get("userDefine.foldersInCode1Close");
const char * sDelimiters = styler.pprops->Get("userDefine.delimiters");
const char * sOperators1 = styler.pprops->Get("userDefine.operators1");
const char * sComments = styler.pprops->Get("userDefine.comments");
// 'GenerateVector' converts strings into vvstring objects
GenerateVector(commentLineOpen, sComments, "00", 0);
GenerateVector(commentLineContinue, sComments, "01", commentLineOpen.size());
GenerateVector(commentLineClose, sComments, "02", commentLineOpen.size());
GenerateVector(commentOpen, sComments, "03", 0);
GenerateVector(commentClose, sComments, "04", commentOpen.size());
GenerateVector(delim1Open, sDelimiters, "00", 0);
GenerateVector(delim1Escape, sDelimiters, "01", delim1Open.size());
GenerateVector(delim1Close, sDelimiters, "02", delim1Open.size());
GenerateVector(delim2Open, sDelimiters, "03", 0);
GenerateVector(delim2Escape, sDelimiters, "04", delim2Open.size());
GenerateVector(delim2Close, sDelimiters, "05", delim2Open.size());
GenerateVector(delim3Open, sDelimiters, "06", 0);
GenerateVector(delim3Escape, sDelimiters, "07", delim3Open.size());
GenerateVector(delim3Close, sDelimiters, "08", delim3Open.size());
GenerateVector(delim4Open, sDelimiters, "09", 0);
GenerateVector(delim4Escape, sDelimiters, "10", delim4Open.size());
GenerateVector(delim4Close, sDelimiters, "11", delim4Open.size());
GenerateVector(delim5Open, sDelimiters, "12", 0);
GenerateVector(delim5Escape, sDelimiters, "13", delim5Open.size());
GenerateVector(delim5Close, sDelimiters, "14", delim5Open.size());
GenerateVector(delim6Open, sDelimiters, "15", 0);
GenerateVector(delim6Escape, sDelimiters, "16", delim6Open.size());
GenerateVector(delim6Close, sDelimiters, "17", delim6Open.size());
GenerateVector(delim7Open, sDelimiters, "18", 0);
GenerateVector(delim7Escape, sDelimiters, "19", delim7Open.size());
GenerateVector(delim7Close, sDelimiters, "20", delim7Open.size());
GenerateVector(delim8Open, sDelimiters, "21", 0);
GenerateVector(delim8Escape, sDelimiters, "22", delim8Open.size());
GenerateVector(delim8Close, sDelimiters, "23", delim8Open.size());
operators1.clear();
foldersInCode1Open.clear();
foldersInCode1Middle.clear();
foldersInCode1Close.clear();
SubGroup(sFoldersInCode1Open, foldersInCode1Open, true);
SubGroup(sFoldersInCode1Middle, foldersInCode1Middle, true);
SubGroup(sFoldersInCode1Close, foldersInCode1Close, true);
SubGroup(sOperators1, operators1, true);
char * numberPrefix1 = (char *)styler.pprops->Get("userDefine.numberPrefix1");
char * numberPrefix2 = (char *)styler.pprops->Get("userDefine.numberPrefix2");
char * numberExtras1 = (char *)styler.pprops->Get("userDefine.numberExtras1");
char * numberExtras2 = (char *)styler.pprops->Get("userDefine.numberExtras2");
char * numberSuffix1 = (char *)styler.pprops->Get("userDefine.numberSuffix1");
char * numberSuffix2 = (char *)styler.pprops->Get("userDefine.numberSuffix2");
char * numberRange = (char *)styler.pprops->Get("userDefine.numberRange");
prefixTokens1.clear();
prefixTokens2.clear();
extrasTokens1.clear();
extrasTokens2.clear();
suffixTokens1.clear();
suffixTokens2.clear();
rangeTokens.clear();
negativePrefixTokens1.clear();
negativePrefixTokens2.clear();
negativeExtrasTokens2.clear();
// 'StringToVector' converts strings into vector<string> objects
StringToVector(numberPrefix1, prefixTokens1);
StringToVector(numberPrefix1, negativePrefixTokens1, true);
StringToVector(numberPrefix2, prefixTokens2);
StringToVector(numberPrefix2, negativePrefixTokens2, true);
StringToVector(numberExtras1, extrasTokens1);
StringToVector(numberExtras2, extrasTokens2);
StringToVector(numberExtras2, negativeExtrasTokens2, true);
StringToVector(numberSuffix1, suffixTokens1);
StringToVector(numberSuffix2, suffixTokens2);
StringToVector(numberRange, rangeTokens);
}
// forward strings are actually kept in forwardStruct's, this allows easy access to ScintillaID and MaskID
// FWS is a single global object used only to create temporary forwardStruct objects that are copied into vector
vector<forwardStruct> forwards;
forwards.push_back(*FWS.Set(&delim1Open, SCE_USER_STYLE_DELIMITER1, SCE_USER_MASK_NESTING_DELIMITER1));
forwards.push_back(*FWS.Set(&delim2Open, SCE_USER_STYLE_DELIMITER2, SCE_USER_MASK_NESTING_DELIMITER2));
forwards.push_back(*FWS.Set(&delim3Open, SCE_USER_STYLE_DELIMITER3, SCE_USER_MASK_NESTING_DELIMITER3));
forwards.push_back(*FWS.Set(&delim4Open, SCE_USER_STYLE_DELIMITER4, SCE_USER_MASK_NESTING_DELIMITER4));
forwards.push_back(*FWS.Set(&delim5Open, SCE_USER_STYLE_DELIMITER5, SCE_USER_MASK_NESTING_DELIMITER5));
forwards.push_back(*FWS.Set(&delim6Open, SCE_USER_STYLE_DELIMITER6, SCE_USER_MASK_NESTING_DELIMITER6));
forwards.push_back(*FWS.Set(&delim7Open, SCE_USER_STYLE_DELIMITER7, SCE_USER_MASK_NESTING_DELIMITER7));
forwards.push_back(*FWS.Set(&delim8Open, SCE_USER_STYLE_DELIMITER8, SCE_USER_MASK_NESTING_DELIMITER8));
forwards.push_back(*FWS.Set(&commentOpen, SCE_USER_STYLE_COMMENT, SCE_USER_MASK_NESTING_COMMENT));
forwards.push_back(*FWS.Set(&commentLineOpen, SCE_USER_STYLE_COMMENTLINE, SCE_USER_MASK_NESTING_COMMENT_LINE));
forwards.push_back(*FWS.Set(&operators1, SCE_USER_STYLE_OPERATOR, SCE_USER_MASK_NESTING_OPERATORS1));
// keep delimiter open strings in an array for easier looping
vvstring * delimStart[SCE_USER_TOTAL_DELIMITERS];
delimStart[0] = &delim1Open;
delimStart[1] = &delim2Open;
delimStart[2] = &delim3Open;
delimStart[3] = &delim4Open;
delimStart[4] = &delim5Open;
delimStart[5] = &delim6Open;
delimStart[6] = &delim7Open;
delimStart[7] = &delim8Open;
vvstring * fwEndVectors[FW_VECTORS_TOTAL]; // array of forward end vectors for multi-part forward search
fwEndVectors[0] = &operators1;
fwEndVectors[1] = &commentLineOpen;
fwEndVectors[2] = &commentLineContinue;
fwEndVectors[3] = &commentLineClose;
fwEndVectors[4] = &commentOpen;
fwEndVectors[5] = &commentClose;
fwEndVectors[6] = &foldersInCode1Open;
fwEndVectors[7] = &foldersInCode1Middle;
fwEndVectors[8] = &foldersInCode1Close;
fwEndVectors[9] = &delim1Close;
fwEndVectors[10] = &delim2Close;
fwEndVectors[11] = &delim3Close;
fwEndVectors[12] = &delim4Close;
fwEndVectors[13] = &delim5Close;
fwEndVectors[14] = &delim6Close;
fwEndVectors[15] = &delim7Close;
fwEndVectors[16] = &delim8Close;
// keep delimiter escape/close strings in an array for easier looping
vvstring * delimVectors[(SCE_USER_TOTAL_DELIMITERS+2) * 2];
delimVectors[0] = &delim1Escape;
delimVectors[1] = &delim1Close;
delimVectors[2] = &delim2Escape;
delimVectors[3] = &delim2Close;
delimVectors[4] = &delim3Escape;
delimVectors[5] = &delim3Close;
delimVectors[6] = &delim4Escape;
delimVectors[7] = &delim4Close;
delimVectors[8] = &delim5Escape;
delimVectors[9] = &delim5Close;
delimVectors[10] = &delim6Escape;
delimVectors[11] = &delim6Close;
delimVectors[12] = &delim7Escape;
delimVectors[13] = &delim7Close;
delimVectors[14] = &delim8Escape;
delimVectors[15] = &delim8Close;
// last four are needed just to create numberDelimSeparators
// they are not used anywhere else
delimVectors[16] = NULL;;
delimVectors[17] = &commentClose;
delimVectors[18] = NULL;
delimVectors[19] = NULL;
// again, loops make our lifes easier
int delimNestings[SCE_USER_TOTAL_DELIMITERS+2];
delimNestings[0] = delim1Nesting;
delimNestings[1] = delim2Nesting;
delimNestings[2] = delim3Nesting;
delimNestings[3] = delim4Nesting;
delimNestings[4] = delim5Nesting;
delimNestings[5] = delim6Nesting;
delimNestings[6] = delim7Nesting;
delimNestings[7] = delim8Nesting;
// last two are needed just to create numberDelimSeparators
// they are not used anywhere else
delimNestings[8] = commentNesting;
delimNestings[9] = lineCommentNesting;
vvstring * numberDelimSeparators[SCE_USER_TOTAL_DELIMITERS+6][SCE_USER_TOTAL_DELIMITERS+6]; // TODO: define hardcoded values as constants (syncy also for FW_VECTORS_TOTAL)
for (int i=0; i<SCE_USER_TOTAL_DELIMITERS+2; ++i)
{
numberDelimSeparators[i][0] = delimVectors[i*2 + 1];
numberDelimSeparators[i][1] = (delimNestings[i] & SCE_USER_MASK_NESTING_DELIMITER1) ? delimStart[0] : NULL;
numberDelimSeparators[i][2] = (delimNestings[i] & SCE_USER_MASK_NESTING_DELIMITER2) ? delimStart[1] : NULL;
numberDelimSeparators[i][3] = (delimNestings[i] & SCE_USER_MASK_NESTING_DELIMITER3) ? delimStart[2] : NULL;
numberDelimSeparators[i][4] = (delimNestings[i] & SCE_USER_MASK_NESTING_DELIMITER4) ? delimStart[3] : NULL;
numberDelimSeparators[i][5] = (delimNestings[i] & SCE_USER_MASK_NESTING_DELIMITER5) ? delimStart[4] : NULL;
numberDelimSeparators[i][6] = (delimNestings[i] & SCE_USER_MASK_NESTING_DELIMITER6) ? delimStart[5] : NULL;
numberDelimSeparators[i][7] = (delimNestings[i] & SCE_USER_MASK_NESTING_DELIMITER7) ? delimStart[6] : NULL;
numberDelimSeparators[i][8] = (delimNestings[i] & SCE_USER_MASK_NESTING_DELIMITER8) ? delimStart[7] : NULL;
numberDelimSeparators[i][9] = (delimNestings[i] & SCE_USER_MASK_NESTING_COMMENT) ? &commentOpen : NULL;
numberDelimSeparators[i][10] = (delimNestings[i] & SCE_USER_MASK_NESTING_COMMENT_LINE) ? &commentLineOpen : NULL;
numberDelimSeparators[i][11] = (delimNestings[i] & SCE_USER_MASK_NESTING_OPERATORS1) ? &operators1 : NULL;
}
vector<string> * numberTokens[10];
numberTokens[0] = &prefixTokens1;
numberTokens[1] = &prefixTokens2;
numberTokens[2] = &extrasTokens1;
numberTokens[3] = &extrasTokens2;
numberTokens[4] = &suffixTokens1;
numberTokens[5] = &suffixTokens2;
numberTokens[6] = &rangeTokens;
numberTokens[7] = &negativePrefixTokens1;
numberTokens[8] = &negativePrefixTokens2;
numberTokens[9] = &negativeExtrasTokens2;
int levelCurrent = SC_FOLDLEVELBASE;
int lineCurrent = 0;
int levelMinCurrent = 0;
int levelNext = 0;
int levelPrev = 0;
int lev = 0;
bool visibleChars = false;
bool skipVisibleCheck = false;
bool dontMove = false;
bool finished = true;
int checkEOL = EOL_DEFAULT_VALUE;
unsigned int nestedLevel = 0;
int openIndex = 0;
int skipForward = 0;
int prevState = 0;
int isCommentLine = COMMENTLINE_NO;
int isPrevLineComment = COMMENTLINE_NO;
bool isInCommentBlock = false;
bool isInComment = false;
int newState = 0;
int nlCount = 0;
int continueCommentBlock = 0;
bool startOfDelimiter = false;
int decSeparator = SEPARATOR_DOT;
vector<nestedInfo> lastNestedGroup;
vvstring * delimEscape = NULL;
vvstring * delimClose = NULL;
vvstring ** numberDelims = NULL;
int delimNesting = 0;
unsigned int docLength = startPos + length;
if (startPos == 0)
{
// foldVector.clear();
nestedVector.clear();
lastNestedGroup.clear();
initStyle = SCE_USER_STYLE_IDENTIFIER;
}
else
{
int oldStartPos = startPos;
ReColoringCheck(startPos, nestedLevel, initStyle, openIndex, isCommentLine, isInComment,
styler, lastNestedGroup, nestedVector, /* foldVector, */ continueCommentBlock);
// offset move to previous line
length += (oldStartPos - startPos);
docLength = startPos + length;
}
lineCurrent = styler.GetLine(startPos);
if (lineCurrent > 0)
levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16;
levelMinCurrent = levelCurrent;
levelNext = levelCurrent;
StyleContext sc(startPos, length, initStyle, styler);
for (; finished; )
{
dontMove = false;
checkEOL = EOL_DEFAULT_VALUE;
if (sc.More() == false)
finished = false; // colorize last word, even if file does not end with whitespace char
switch (sc.state)
{
case SCE_USER_STYLE_DELIMITER1:
case SCE_USER_STYLE_DELIMITER2:
case SCE_USER_STYLE_DELIMITER3:
case SCE_USER_STYLE_DELIMITER4:
case SCE_USER_STYLE_DELIMITER5:
case SCE_USER_STYLE_DELIMITER6:
case SCE_USER_STYLE_DELIMITER7:
case SCE_USER_STYLE_DELIMITER8:
{
int index = sc.state - SCE_USER_STYLE_DELIMITER1;
delimEscape = delimVectors[index*2];
delimClose = delimVectors[index*2 + 1];
delimNesting = delimNestings[index];
numberDelims = numberDelimSeparators[index];
prevState = sc.state;
newState = sc.state;
// first, check escape sequence
bool loopEscape = true;
vector<string>::iterator iter;
while (loopEscape == true)
{
loopEscape = false;
iter = (*delimEscape)[openIndex].begin();
for (; iter != (*delimEscape)[openIndex].end(); ++iter)
{
if (ignoreCase?sc.MatchIgnoreCase2(iter->c_str()):sc.Match(iter->c_str()))
{
sc.Forward(iter->length() + 1); // escape is found, skip escape string and one char after it.
loopEscape = true;
//break;
}
}
}
// second, check end of delimiter sequence
iter = (*delimClose)[openIndex].begin();
for (; iter != (*delimClose)[openIndex].end(); ++iter)
{
if (ignoreCase ? sc.MatchIgnoreCase2(iter->c_str()):sc.Match(iter->c_str()))
{
// record end of delimiter sequence (NI_CLOSE)
nestedVector.push_back(*NI.Set(sc.currentPos + iter->length() - 1, nestedLevel--, openIndex, sc.state, NI_CLOSE));
// is there anything on the left side? (any backward keyword 'glued' with end of delimiter sequence)
setBackwards(kwLists, sc, prefixes, ignoreCase, delimNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
// paint backward keyword
sc.SetState(prevState);
// was current delimiter sequence nested, or do we start over from SCE_USER_STYLE_IDENTIFIER?
readLastNested(lastNestedGroup, newState, openIndex);
// for delimiters that end with ((EOL))
if (newState != SCE_USER_STYLE_COMMENTLINE || (sc.ch != '\r' && sc.ch != '\n'))
sc.Forward(iter->length());
if (sc.atLineStart)
checkEOL = EOL_FORCE_CHECK;
// paint end of delimiter sequence
sc.SetState(newState);
dontMove = true;
break; // break out of 'for', not 'case'
}
}
// out of current state?
if (prevState != newState)
break;
// quick replacement for SCE_USER_STYLE_DEFAULT (important for nested keywords)
if (isWhiteSpace(sc.ch) && !isWhiteSpace(sc.chPrev))
{
setBackwards(kwLists, sc, prefixes, ignoreCase, delimNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
sc.SetState(prevState);
}
else if ((!isWhiteSpace(sc.ch) && isWhiteSpace(sc.chPrev)))
{
// create new 'compare point' (AKA beginning of nested keyword) before checking for numbers
sc.SetState(prevState);
}
// third, check nested delimiter sequence
if (isInListNested(delimNesting, forwards, sc, ignoreCase, openIndex, skipForward,
newState, pureLC, visibleChars, numberTokens, numberDelims, decSeparator))
{
// any backward keyword 'glued' on the left side?
setBackwards(kwLists, sc, prefixes, ignoreCase, delimNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
if (newState != SCE_USER_STYLE_OPERATOR && newState != SCE_USER_STYLE_NUMBER)
{
// record delimiter sequence in BOTH vectors
nestedVector.push_back(*NI.Set(sc.currentPos, ++nestedLevel, openIndex, newState, NI_OPEN));
lastNestedGroup.push_back(NI);
}
sc.SetState(newState); // yes, both 'SetState' calls are needed
sc.Forward(skipForward);
sc.SetState(newState);
if (newState == SCE_USER_STYLE_OPERATOR || newState == SCE_USER_STYLE_NUMBER)
sc.ChangeState(prevState);
dontMove = true;
break;
}
break;
}
case SCE_USER_STYLE_COMMENT:
{
numberDelims = numberDelimSeparators[SCE_USER_TOTAL_DELIMITERS];
// first, check end of comment sequence
vector<string>::iterator iter = commentClose[openIndex].begin();
for (; iter != commentClose[openIndex].end(); ++iter)
{
if (ignoreCase?sc.MatchIgnoreCase2(iter->c_str()):sc.Match(iter->c_str()))
{
// record end of comment sequence (NI_CLOSE)
nestedVector.push_back(*NI.Set(sc.currentPos + iter->length() - 1, nestedLevel--, openIndex, SCE_USER_STYLE_COMMENT, NI_CLOSE));
// is there anything on the left side? (any backward keyword 'glued' with end of comment sequence)
setBackwards(kwLists, sc, prefixes, ignoreCase, commentNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
// paint backward keyword and move on
sc.SetState(SCE_USER_STYLE_COMMENT);
sc.Forward(iter->length());
// was current comment sequence nested, or do we start over from SCE_USER_STYLE_IDENTIFIER?
readLastNested(lastNestedGroup, newState, openIndex);
// paint end of comment sequence
sc.SetState(newState);
isInComment = false;
dontMove = true;
break;
}
}
if (sc.state != SCE_USER_STYLE_COMMENT)
break;
// quick replacement for SCE_USER_STYLE_DEFAULT (important for nested keywords)
if (isWhiteSpace(sc.ch) && !isWhiteSpace(sc.chPrev))
{
setBackwards(kwLists, sc, prefixes, ignoreCase, commentNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
sc.SetState(SCE_USER_STYLE_COMMENT);
}
else if (!isWhiteSpace(sc.ch) && isWhiteSpace(sc.chPrev))
{
// create new 'compare point' (AKA beginning of nested keyword) before checking for numbers
sc.SetState(SCE_USER_STYLE_COMMENT);
}
// third, check nested delimiter sequence
if (isInListNested(commentNesting, forwards, sc, ignoreCase, openIndex, skipForward,
newState, pureLC, visibleChars, numberTokens, numberDelims, decSeparator))
{
// any backward keyword 'glued' on the left side?
setBackwards(kwLists, sc, prefixes, ignoreCase, commentNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
if (newState != SCE_USER_STYLE_OPERATOR && newState != SCE_USER_STYLE_NUMBER)
{
// record delimiter sequence in BOTH vectors
nestedVector.push_back(*NI.Set(sc.currentPos, ++nestedLevel, openIndex, newState, NI_OPEN));
lastNestedGroup.push_back(NI);
}
sc.SetState(newState); // yes, both 'SetState' calls are needed
sc.Forward(skipForward);
sc.SetState(newState);
if (newState == SCE_USER_STYLE_OPERATOR || newState == SCE_USER_STYLE_NUMBER)
sc.ChangeState(SCE_USER_STYLE_COMMENT);
dontMove = true;
break;
}
break;
}
case SCE_USER_STYLE_COMMENTLINE:
{
numberDelims = numberDelimSeparators[SCE_USER_TOTAL_DELIMITERS + 1];
// first, check end of line comment sequence (in rare cases when line comments can end before new line char)
vector<string>::iterator iter = commentLineClose[openIndex].begin();
for (; iter != commentLineClose[openIndex].end(); ++iter)
{
if (ignoreCase?sc.MatchIgnoreCase2(iter->c_str()):sc.Match(iter->c_str()))
{
// record end of line comment sequence (NI_CLOSE)
nestedVector.push_back(*NI.Set(sc.currentPos + iter->length() - 1, nestedLevel--, openIndex, SCE_USER_STYLE_COMMENTLINE, NI_CLOSE));
// is there anything on the left side? (any backward keyword 'glued' with end of line comment sequence)
setBackwards(kwLists, sc, prefixes, ignoreCase, lineCommentNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
// paint backward keyword and move on
sc.SetState(SCE_USER_STYLE_COMMENTLINE);
sc.Forward(iter->length());
// was current line comment sequence nested, or do we start over from SCE_USER_STYLE_IDENTIFIER?
readLastNested(lastNestedGroup, newState, openIndex);
// paint end of line comment sequence
sc.SetState(newState);
dontMove = true;
break; // break out of 'for', not 'case'
}
}
if (sc.state != SCE_USER_STYLE_COMMENTLINE)
break;
// quick replacement for SCE_USER_STYLE_DEFAULT (important for nested keywords)
if (isWhiteSpace(sc.ch) && !isWhiteSpace(sc.chPrev))
{
setBackwards(kwLists, sc, prefixes, ignoreCase, lineCommentNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
sc.SetState(SCE_USER_STYLE_COMMENTLINE);
}
else if (!isWhiteSpace(sc.ch) && isWhiteSpace(sc.chPrev))
{
// create new 'compare point' (AKA beginning of nested keyword) before checking for numbers
sc.SetState(SCE_USER_STYLE_COMMENTLINE);
}
// second, check line comment continuation
if (sc.atLineEnd)
{
bool lineContinuation = false;
int offset = 0;
if (sc.chPrev == '\r')
offset = 1;
vector<string>::iterator iter = commentLineContinue[openIndex].begin();
for (; iter != commentLineContinue[openIndex].end(); ++iter)
{
int length = iter->length();
if (length == 0)
{
if (!dontMove)
sc.Forward();
continue;
}
lineContinuation = true;
for (int i=0; i<length; ++i)
{
if (ignoreCase)
{
if (toupper((*iter)[i]) != toupper(styler.SafeGetCharAt(sc.currentPos - length + i - offset, 0)))
{
lineContinuation = false;
break;
}
}
else if ((*iter)[i] != styler.SafeGetCharAt(sc.currentPos - length + i - offset, 0))
{
lineContinuation = false;
break;
}
}
// if line comment continuation string is found at EOL, treat next line as a comment line
if (lineContinuation)
{
isCommentLine = COMMENTLINE_YES;
break; // break out of 'for', not 'case'
}
}
sc.ChangeState(SCE_USER_STYLE_COMMENTLINE); // no need to paint, only change state for now
if (!lineContinuation)
{
// paint \n character too (or \r for old MAc format)
sc.Forward();
dontMove = true;
checkEOL = EOL_FORCE_CHECK;
// record end of line comment sequence (NI_CLOSE)
nestedVector.push_back(*NI.Set(sc.currentPos - 1, nestedLevel--, openIndex, SCE_USER_STYLE_COMMENTLINE, NI_CLOSE));
// was current line comment sequence nested, or do we start over from SCE_USER_STYLE_IDENTIFIER?
readLastNested(lastNestedGroup, newState, openIndex);
// paint entire line comment sequence in one step
sc.SetState(newState);
}
lineContinuation = false;
break;
}
if (sc.state != SCE_USER_STYLE_COMMENTLINE)
break;
// third, check nested delimiter sequence
if (isInListNested(lineCommentNesting, forwards, sc, ignoreCase, openIndex, skipForward,
newState, pureLC, visibleChars, numberTokens, numberDelims, decSeparator))
{
// any backward keyword 'glued' on the left side?
setBackwards(kwLists, sc, prefixes, ignoreCase, lineCommentNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
if (newState != SCE_USER_STYLE_OPERATOR && newState != SCE_USER_STYLE_NUMBER)
{
// record delimiter sequence in BOTH vectors
nestedVector.push_back(*NI.Set(sc.currentPos, ++nestedLevel, openIndex, newState, NI_OPEN));
lastNestedGroup.push_back(NI);
}
sc.SetState(newState); // yes, both 'SetState' calls are needed
sc.Forward(skipForward);
sc.SetState(newState);
if (newState == SCE_USER_STYLE_OPERATOR || newState == SCE_USER_STYLE_NUMBER)
sc.ChangeState(SCE_USER_STYLE_COMMENTLINE);
dontMove = true;
break;
}
break;
}
case SCE_USER_STYLE_DEFAULT:
{
if (isWhiteSpace(sc.ch))
{
setBackwards(kwLists, sc, prefixes, ignoreCase, bwNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
sc.SetState(SCE_USER_STYLE_IDENTIFIER);
break;
}
if (!commentLineOpen.empty())
{
if ((pureLC == PURE_LC_NONE) ||
(pureLC == PURE_LC_BOL && (sc.chPrev == '\r' || sc.chPrev == '\n')) ||
(pureLC == PURE_LC_WSP && visibleChars == false) )
{
if (isInListForward(commentLineOpen, sc, ignoreCase, openIndex, skipForward))
{
if (foldComments && isCommentLine != COMMENTLINE_SKIP_TESTING)
isCommentLine = COMMENTLINE_YES;
// any backward keyword 'glued' on the left side?
setBackwards(kwLists, sc, prefixes, ignoreCase, bwNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
// paint up to start of line comment sequence
sc.SetState(SCE_USER_STYLE_COMMENTLINE);
// record start of line comment sequence (NI_OPEN) in BOTH vectors
nestedVector.push_back(*NI.Set(sc.currentPos, ++nestedLevel, openIndex, SCE_USER_STYLE_COMMENTLINE, NI_OPEN));
lastNestedGroup.push_back(NI);
// paint start of line comment sequence
sc.Forward(skipForward);
sc.SetState(SCE_USER_STYLE_COMMENTLINE);
dontMove = true;
if (sc.atLineEnd)
checkEOL = EOL_SKIP_CHECK;
if (lineCommentNesting & SCE_USER_MASK_NESTING_NUMBERS)
startOfDelimiter = true;
break;
}
}
}
if (!commentOpen.empty())
{
if (isInListForward(commentOpen, sc, ignoreCase, openIndex, skipForward))
{
if (foldComments)
{
isInComment = true;
if (isCommentLine != COMMENTLINE_SKIP_TESTING)
isCommentLine = COMMENTLINE_YES;
}
// any backward keyword 'glued' on the left side?
setBackwards(kwLists, sc, prefixes, ignoreCase, bwNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
// paint up to start of comment sequence
sc.SetState(SCE_USER_STYLE_COMMENT);
// record start of comment sequence (NI_OPEN) in BOTH nesting vectors
nestedVector.push_back(*NI.Set(sc.currentPos, ++nestedLevel, openIndex, SCE_USER_STYLE_COMMENT, NI_OPEN));
lastNestedGroup.push_back(NI);
// paint start of comment sequence
sc.Forward(skipForward);
sc.SetState(SCE_USER_STYLE_COMMENT);
dontMove = true;
if (sc.atLineEnd)
checkEOL = EOL_SKIP_CHECK;
if (commentNesting & SCE_USER_MASK_NESTING_NUMBERS)
startOfDelimiter = true;
break;
}
}
for (int i=0; i<SCE_USER_TOTAL_DELIMITERS; ++i)
{
if (!delimStart[i]->empty())
{
if (isInListForward(*delimStart[i], sc, ignoreCase, openIndex, skipForward))
{
// any backward keyword 'glued' on the left side?
setBackwards(kwLists, sc, prefixes, ignoreCase, bwNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
// paint up to start of delimiter sequence
sc.SetState(i+SCE_USER_STYLE_DELIMITER1);
// record start of delimiter sequence (NI_OPEN) in BOTH nesting vectors
nestedVector.push_back(*NI.Set(sc.currentPos, ++nestedLevel, openIndex, i+SCE_USER_STYLE_DELIMITER1, NI_OPEN));
lastNestedGroup.push_back(NI);
// paint start of delimiter sequence
sc.Forward(skipForward);
sc.SetState(i+SCE_USER_STYLE_DELIMITER1);
dontMove = true;
if (sc.atLineEnd)
checkEOL = EOL_SKIP_CHECK;
break; // break from nested 'for' loop, not 'case' statement
}
}
}
if (dontMove == true)
break; // delimiter start found, break from case SCE_USER_STYLE_DEFAULT
if (!operators1.empty())
{
if (isInListForward(operators1, sc, ignoreCase, openIndex, skipForward))
{
// any backward keyword 'glued' on the left side?
setBackwards(kwLists, sc, prefixes, ignoreCase, bwNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
// paint up to start of sequence
sc.SetState(SCE_USER_STYLE_OPERATOR);
// paint sequence
sc.Forward(skipForward);
//sc.ChangeState(SCE_USER_STYLE_OPERATOR);
// no closing sequence, start over from default
sc.SetState(SCE_USER_STYLE_IDENTIFIER);
dontMove = true;
break;
}
}
if (!foldersInCode1Open.empty())
{
if (isInListForward(foldersInCode1Open, sc, ignoreCase, openIndex, skipForward))
{
// any backward keyword 'glued' on the left side?
setBackwards(kwLists, sc, prefixes, ignoreCase, bwNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
// paint up to start of sequence
sc.SetState(SCE_USER_STYLE_FOLDER_IN_CODE1);
// paint sequence
sc.Forward(skipForward);
//sc.ChangeState(SCE_USER_STYLE_FOLDER_IN_CODE1);
// no closing sequence, start over from default
sc.SetState(SCE_USER_STYLE_IDENTIFIER);
dontMove = true;
if (sc.atLineEnd)
checkEOL = EOL_SKIP_CHECK;
if (levelMinCurrent > levelNext)
levelMinCurrent = levelNext;
levelNext++;
break;
}
}
if (!foldersInCode1Middle.empty())
{
if (isInListForward(foldersInCode1Middle, sc, ignoreCase, openIndex, skipForward))
{
// any backward keyword 'glued' on the left side?
setBackwards(kwLists, sc, prefixes, ignoreCase, bwNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
// paint up to start of sequence
sc.SetState(SCE_USER_STYLE_FOLDER_IN_CODE1);
// paint sequence
sc.Forward(skipForward);
//sc.ChangeState(SCE_USER_STYLE_FOLDER_IN_CODE1);
// no closing sequence, start over from default
sc.SetState(SCE_USER_STYLE_IDENTIFIER);
dontMove = true;
if (sc.atLineEnd)
checkEOL = true;
levelNext--;
if (levelMinCurrent > levelNext)
levelMinCurrent = levelNext;
levelNext++;
break;
}
}
if (!foldersInCode1Close.empty())
{
if (isInListForward(foldersInCode1Close, sc, ignoreCase, openIndex, skipForward))
{
// any backward keyword 'glued' on the left side?
setBackwards(kwLists, sc, prefixes, ignoreCase, bwNesting, fwEndVectors, levelMinCurrent, levelNext, nlCount, dontMove, docLength);
// paint up to start of sequence
sc.SetState(SCE_USER_STYLE_FOLDER_IN_CODE1);
// paint sequence
sc.Forward(skipForward);
//sc.ChangeState(SCE_USER_STYLE_FOLDER_IN_CODE1);
// no closing sequence, start over from default
sc.SetState(SCE_USER_STYLE_IDENTIFIER);
if (sc.atLineEnd)
checkEOL = true;
dontMove = true;
levelNext--;
break;
}
}
if (foldComments && isCommentLine != COMMENTLINE_SKIP_TESTING)
isCommentLine = COMMENTLINE_SKIP_TESTING;
break;
}
// determine if a new state should be entered.
case SCE_USER_STYLE_IDENTIFIER:
{
if (isWhiteSpace(sc.ch))
break;
if (IsNumber(sc, numberTokens, fwEndVectors, ignoreCase, decSeparator, skipForward))
{
// paint up to start of sequence
sc.SetState(SCE_USER_STYLE_NUMBER);
// paint sequence
sc.Forward(skipForward);
//sc.ChangeState(SCE_USER_STYLE_NUMBER);
// start over from default
sc.SetState(SCE_USER_STYLE_IDENTIFIER);
if (isWhiteSpace(sc.ch))
break;
}
if (!isWhiteSpace(sc.ch))// && isWhiteSpace(sc.chPrev)) // word start
{
sc.SetState(SCE_USER_STYLE_DEFAULT);
skipVisibleCheck = true;
dontMove = true;
break;
}
break;
}
default:
break;
}
if (foldComments)
if (isInComment == false)
if (isCommentLine == COMMENTLINE_NO)
if (sc.state != SCE_USER_STYLE_COMMENTLINE)
if (sc.state != SCE_USER_STYLE_IDENTIFIER)
if (sc.state != SCE_USER_STYLE_DEFAULT)
if (!isWhiteSpace(sc.ch))
isCommentLine = COMMENTLINE_SKIP_TESTING;
if (skipVisibleCheck == true)
skipVisibleCheck = false;
else if (visibleChars == false && !isWhiteSpace(sc.ch))
visibleChars = true;
if ((sc.atLineEnd == true && checkEOL != EOL_SKIP_CHECK) || (sc.atLineEnd == false && checkEOL == EOL_FORCE_CHECK))
{
if (foldComments == true)
{
if (levelCurrent != levelNext)
isCommentLine = COMMENTLINE_SKIP_TESTING;
if (continueCommentBlock > 0)
{
if (continueCommentBlock & CL_PREVPREV)
{
isInCommentBlock = true;
isPrevLineComment = COMMENTLINE_YES;
if (!(continueCommentBlock & CL_CURRENT))
{
levelNext++;
levelMinCurrent++;
levelCurrent++;
levelPrev = (levelMinCurrent | levelNext << 16) | SC_ISCOMMENTLINE;
}
}
else if (continueCommentBlock & CL_PREV)
{
isPrevLineComment = COMMENTLINE_YES;
if (continueCommentBlock & CL_CURRENT)
{
levelMinCurrent--;
levelNext--;
levelCurrent--;
levelPrev = (levelMinCurrent | levelNext << 16) | SC_ISCOMMENTLINE;
}
}
continueCommentBlock = 0;
}
if (isInCommentBlock && isCommentLine != COMMENTLINE_YES && isPrevLineComment == COMMENTLINE_YES)
{
levelNext--;
levelPrev = (levelMinCurrent | levelNext << 16) | SC_ISCOMMENTLINE;
levelMinCurrent--;
isInCommentBlock = false;
}
if (!isInCommentBlock && isCommentLine == COMMENTLINE_YES && isPrevLineComment == COMMENTLINE_YES)
{
levelNext++;
levelPrev = (levelMinCurrent | levelNext << 16) | SC_FOLDLEVELHEADERFLAG | SC_ISCOMMENTLINE;
levelMinCurrent = levelNext;
isInCommentBlock = true;
}
if (levelPrev != 0)
{
// foldVector[lineCurrent - 1] = levelPrev;
styler.SetLevel(lineCurrent - 1, levelPrev);
levelPrev = 0;
}
}
lev = levelMinCurrent | levelNext << 16;
if (foldComments && isCommentLine == COMMENTLINE_YES)
lev |= SC_ISCOMMENTLINE;
if (visibleChars == false && foldCompact)
lev |= SC_FOLDLEVELWHITEFLAG;
if (levelMinCurrent < levelNext)
lev |= SC_FOLDLEVELHEADERFLAG;
// foldVector.push_back(lev);
styler.SetLevel(lineCurrent, lev);
for (int i=0; i<nlCount; ++i) // multi-line multi-part keyword
{
// foldVector.push_back(levelNext | levelNext << 16); // TODO: what about SC_ISCOMMENTLINE?
styler.SetLevel(lineCurrent++, levelNext | levelNext << 16);
}
nlCount = 0;
lineCurrent++;
levelCurrent = levelNext;
levelMinCurrent = levelCurrent;
visibleChars = false;
if (foldComments)
{
isPrevLineComment = isCommentLine==COMMENTLINE_YES ? COMMENTLINE_YES:COMMENTLINE_NO;
isCommentLine = isInComment ? COMMENTLINE_YES:COMMENTLINE_NO;
}
}
if (!dontMove)
sc.Forward();
}
sc.Complete();
}
static void FoldUserDoc(unsigned int /* startPos */, int /* length */, int /*initStyle*/, WordList *[], Accessor & /* styler */)
{
// this function will not be used in final version of the code.
// it should remain commented out as it is useful for debugging purposes !!!
// perhaps ifdef block would be a wiser choice, but commenting out works just fine for the time being
// int lineCurrent = styler.GetLine(startPos);
// vector<int>::iterator iter = foldVectorStatic->begin() + lineCurrent;
// for (; iter != foldVectorStatic->end(); ++iter)
// {
// styler.SetLevel(lineCurrent++, *iter);
// }
}
static const char * const userDefineWordLists[] = {
"Primary keywords and identifiers",
"Secondary keywords and identifiers",
"Documentation comment keywords",
"Fold header keywords",
0,
};
LexerModule lmUserDefine(SCLEX_USER, ColouriseUserDoc, "user", FoldUserDoc, userDefineWordLists);