2009-04-24 23:35:41 +00:00
/*------------------------------------------------------------------------------------
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 0213 9 , USA .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2013-08-28 00:44:27 +00:00
2012-09-28 21:04:16 +00:00
# include <string>
# include <map>
# include <vector>
2010-08-22 02:20:44 +00:00
# include <assert.h>
2009-04-24 23:35:41 +00:00
# include <windows.h>
2010-08-22 02:20:44 +00:00
# include "ILexer.h"
# include "LexAccessor.h"
2009-04-24 23:35:41 +00:00
# include "Accessor.h"
# include "StyleContext.h"
2010-08-22 02:20:44 +00:00
# include "WordList.h"
2009-04-24 23:35:41 +00:00
# include "Scintilla.h"
2014-01-05 23:15:13 +00:00
# include "SciLexer.h"
2010-08-22 02:20:44 +00:00
# include "LexerModule.h"
2012-09-28 21:04:16 +00:00
# include "PropSetSimple.h"
2013-08-28 00:44:27 +00:00
2012-09-28 21:04:16 +00:00
using namespace Scintilla ;
# 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
2012-10-20 16:20:57 +00:00
# define SEPARATOR_DOT 0
# define SEPARATOR_COMMA 1
# define SEPARATOR_BOTH 2
2012-09-28 21:04:16 +00:00
# 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
2013-01-27 01:03:53 +00:00
# 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
2012-09-28 21:04:16 +00:00
# define MAPPER_TOTAL 15
2013-01-27 01:03:53 +00:00
# define FW_VECTORS_TOTAL SCE_USER_TOTAL_DELIMITERS + 9
2012-09-28 21:04:16 +00:00
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
{
2019-05-04 18:14:48 +00:00
vvstring * _vec ;
int _sceID ;
int _maskID ;
2012-09-28 21:04:16 +00:00
2019-05-04 18:14:48 +00:00
forwardStruct ( ) : _vec ( 0 ) , _sceID ( 0 ) , _maskID ( 0 ) { } ; // constructor, useless but obligatory
2012-09-28 21:04:16 +00:00
forwardStruct * Set ( vvstring * vec , int sceID , int maskID ) {
2019-05-04 18:14:48 +00:00
_vec = vec ;
_sceID = sceID ;
_maskID = maskID ;
2012-09-28 21:04:16 +00:00
return this ;
}
2009-04-24 23:35:41 +00:00
2012-09-28 21:04:16 +00:00
} FWS ; // just one instance
2010-08-22 02:20:44 +00:00
2012-09-28 21:04:16 +00:00
struct nestedInfo {
2019-05-04 18:14:48 +00:00
size_t _position ;
int _nestedLevel ;
int _index ;
int _state ;
int _opener ;
2010-08-22 02:20:44 +00:00
2012-09-28 21:04:16 +00:00
// constructor, useless but obligatory
2019-05-04 18:14:48 +00:00
nestedInfo ( ) : _position ( 0 ) , _nestedLevel ( 0 ) , _index ( 0 ) , _state ( 0 ) , _opener ( 0 ) { } ;
nestedInfo * Set ( size_t position , int nestedLevel , int index , int state , int opener ) {
_position = position ;
_nestedLevel = nestedLevel ;
_index = index ;
_state = state ;
_opener = opener ;
2012-09-28 21:04:16 +00:00
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 ;
2012-10-20 16:20:57 +00:00
vector < string > prefixTokens1 ;
vector < string > prefixTokens2 ;
2013-01-27 01:03:53 +00:00
vector < string > suffixTokens1 ;
vector < string > suffixTokens2 ;
vector < string > extrasTokens1 ;
vector < string > extrasTokens2 ;
vector < string > rangeTokens ;
2012-10-20 16:20:57 +00:00
vector < string > negativePrefixTokens1 ;
vector < string > negativePrefixTokens2 ;
2013-01-27 01:03:53 +00:00
vector < string > negativeExtrasTokens2 ;
2012-09-28 21:04:16 +00:00
} ;
// 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 ) ;
2010-08-22 02:20:44 +00:00
}
2012-09-28 21:04:16 +00:00
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 ) ;
2010-08-22 02:20:44 +00:00
}
2012-10-20 16:20:57 +00:00
static bool isInListForward2 ( vvstring * fwEndVectors [ ] , int totalVectors , StyleContext & sc , bool ignoreCase , int forward )
2009-04-24 23:35:41 +00:00
{
2012-09-28 21:04:16 +00:00
// 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 ;
2012-10-20 16:20:57 +00:00
for ( int i = 0 ; i < totalVectors ; + + i )
2012-09-28 21:04:16 +00:00
{
2012-10-20 16:20:57 +00:00
if ( fwEndVectors [ i ] & & ! fwEndVectors [ i ] - > empty ( ) )
2012-09-28 21:04:16 +00:00
{
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 ;
2009-04-24 23:35:41 +00:00
}
2019-05-04 18:14:48 +00:00
static bool isInListForward3 ( vector < string > * tokens , StyleContext & sc , bool ignoreCase , Sci_Position offset , size_t & moveForward )
2012-10-20 16:20:57 +00:00
{
// forward check for vector<string> keywords, with offset
moveForward = 0 ;
unsigned char a = 0 ;
unsigned char b = 0 ;
2019-05-04 18:14:48 +00:00
Sci_Position indexb = 0 ;
2012-10-20 16:20:57 +00:00
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 ;
}
2012-09-28 21:04:16 +00:00
static inline bool IsADigit ( char ch )
{
return isascii ( ch ) & & isdigit ( ch ) ;
2009-04-24 23:35:41 +00:00
}
2012-10-20 16:20:57 +00:00
static bool IsNumber ( StyleContext & sc , vector < string > * numberTokens [ ] , vvstring * fwEndVectors [ ] ,
2019-05-04 18:14:48 +00:00
bool ignoreCase , int decSeparator , size_t & moveForward )
2012-09-28 21:04:16 +00:00
{
moveForward = 0 ;
2012-10-20 16:20:57 +00:00
bool hasDot = false ;
bool hasPrefix1 = false ;
bool hasPrefix2 = false ;
2013-01-27 01:03:53 +00:00
bool hasSuffix1 = false ;
bool hasSuffix2 = false ;
bool hasExtras2 = false ;
2012-10-20 16:20:57 +00:00
bool hasRange = false ;
bool hasExp = false ;
bool previousWasRange = false ;
2019-05-04 18:14:48 +00:00
Sci_Position offset = 0 ;
2012-10-20 16:20:57 +00:00
vector < string > * prefixTokens1 = numberTokens [ 0 ] ;
vector < string > * prefixTokens2 = numberTokens [ 1 ] ;
2013-01-27 01:03:53 +00:00
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 ] ;
2012-10-20 16:20:57 +00:00
// treat .1234 as correct number sequence
if ( ( ( decSeparator = = SEPARATOR_BOTH | | decSeparator = = SEPARATOR_DOT ) & & sc . ch = = ' . ' ) | |
( ( decSeparator = = SEPARATOR_BOTH | | decSeparator = = SEPARATOR_COMMA ) & & sc . ch = = ' , ' ) )
2012-09-28 21:04:16 +00:00
{
2012-10-20 16:20:57 +00:00
if ( IsADigit ( sc . chNext ) )
{
hasDot = true ;
offset = 2 ;
}
2012-09-28 21:04:16 +00:00
}
2012-10-20 16:20:57 +00:00
else
2012-09-28 21:04:16 +00:00
{
2012-10-20 16:20:57 +00:00
// or is it a prefixed number?
vector < string > : : iterator iter = prefixTokens2 - > begin ( ) ;
vector < string > : : iterator last = prefixTokens2 - > end ( ) ;
if ( sc . ch = = ' - ' )
2012-09-28 21:04:16 +00:00
{
2012-10-20 16:20:57 +00:00
iter = negativePrefixTokens2 - > begin ( ) ;
last = negativePrefixTokens2 - > end ( ) ;
2012-09-28 21:04:16 +00:00
}
2012-10-20 16:20:57 +00:00
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
2019-05-04 18:14:48 +00:00
size_t skipForward = 0 ;
2009-04-24 23:35:41 +00:00
2013-01-27 01:03:53 +00:00
if ( isInListForward3 ( extrasTokens1 , sc , ignoreCase , iter - > length ( ) , skipForward ) )
2012-10-20 16:20:57 +00:00
{
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
}
}
}
2013-01-27 01:03:53 +00:00
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
}
}
2012-10-20 16:20:57 +00:00
}
// is it a simple digit?
if ( offset = = 0 )
2012-09-28 21:04:16 +00:00
{
2012-10-20 16:20:57 +00:00
if ( IsADigit ( sc . ch ) )
{
offset = 1 ;
}
// or prefixed simple digit?
else if ( ( sc . ch = = ' - ' | | sc . ch = = ' + ' ) & & IsADigit ( sc . chNext ) & & ! IsADigit ( sc . chPrev ) )
2012-09-28 21:04:16 +00:00
{
2012-10-20 16:20:57 +00:00
offset = 2 ;
2012-09-28 21:04:16 +00:00
}
2012-10-20 16:20:57 +00:00
if ( offset = = 0 )
return false ;
2012-09-28 21:04:16 +00:00
}
2019-05-04 18:14:48 +00:00
size_t skipForward = 0 ;
2012-10-20 16:20:57 +00:00
for ( ; ; )
2012-09-28 21:04:16 +00:00
{
2012-10-20 16:20:57 +00:00
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 ) )
2012-09-28 21:04:16 +00:00
{
2013-01-27 01:03:53 +00:00
if ( hasExtras2 = = true & & hasSuffix1 = = false )
return false ;
2012-10-20 16:20:57 +00:00
moveForward = offset ;
return true ; // yay, finally we have a number
2012-09-28 21:04:16 +00:00
}
2012-10-20 16:20:57 +00:00
if ( hasRange = = false )
{
if ( isInListForward3 ( rangeTokens , sc , ignoreCase , offset , skipForward ) )
{
2013-01-27 01:03:53 +00:00
if ( hasExtras2 = = true & & hasSuffix1 = = false )
return false ;
2012-10-20 16:20:57 +00:00
offset + = skipForward ;
2013-01-27 01:03:53 +00:00
hasSuffix1 = false ;
hasSuffix2 = false ;
2012-10-20 16:20:57 +00:00
hasDot = false ;
hasRange = true ;
hasExp = false ;
2013-01-27 01:03:53 +00:00
hasExtras2 = false ;
2012-10-20 16:20:57 +00:00
previousWasRange = true ;
continue ;
}
}
2012-09-28 21:04:16 +00:00
2013-01-27 01:03:53 +00:00
if ( hasSuffix2 = = true ) // only RANGE_CHARs are allowed after SUFFIX_CHARs
2012-10-20 16:20:57 +00:00
return false ;
2012-09-28 21:04:16 +00:00
2012-10-20 16:20:57 +00:00
if ( hasPrefix2 = = true )
{
2013-01-27 01:03:53 +00:00
if ( isInListForward3 ( extrasTokens1 , sc , ignoreCase , offset , skipForward ) )
2012-10-20 16:20:57 +00:00
{
offset + = skipForward ;
continue ;
}
}
2012-09-28 21:04:16 +00:00
2013-01-27 01:03:53 +00:00
if ( hasSuffix1 = = false & & hasPrefix1 = = false & & hasPrefix2 = = false )
2012-10-20 16:20:57 +00:00
{
2013-01-27 01:03:53 +00:00
if ( isInListForward3 ( suffixTokens1 , sc , ignoreCase , offset , skipForward ) )
{
offset + = skipForward ;
hasExtras2 = false ;
hasSuffix1 = true ;
continue ;
}
if ( isInListForward3 ( extrasTokens2 , sc , ignoreCase , offset , skipForward ) )
2012-10-20 16:20:57 +00:00
{
offset + = skipForward ;
2013-01-27 01:03:53 +00:00
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 ;
2012-10-20 16:20:57 +00:00
continue ;
}
}
2012-09-28 21:04:16 +00:00
2012-10-20 16:20:57 +00:00
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 ;
}
2012-09-28 21:04:16 +00:00
2012-10-20 16:20:57 +00:00
if ( isInListForward3 ( prefixTokens1 , sc , ignoreCase , offset , skipForward ) )
{
offset + = skipForward ;
hasExp = false ;
hasPrefix1 = true ;
continue ;
}
}
2012-09-28 21:04:16 +00:00
2012-10-20 16:20:57 +00:00
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 ;
}
2009-04-24 23:35:41 +00:00
}
2012-09-28 21:04:16 +00:00
static inline void SubGroup ( const char * s , vvstring & vec , bool group = false )
2009-04-24 23:35:41 +00:00
{
2019-05-04 18:14:48 +00:00
size_t length = strlen ( s ) ;
2012-09-28 21:04:16 +00:00
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 ;
2015-06-11 09:22:05 +00:00
if ( length > = 2 & & s [ 0 ] = = ' ( ' & & s [ 1 ] = = ' ( ' )
2012-09-28 21:04:16 +00:00
{
i = 2 ;
group = true ;
}
2015-06-11 09:22:05 +00:00
if ( length > = 2 & & s [ length - 1 ] = = ' ) ' & & s [ length - 2 ] = = ' ) ' )
2012-09-28 21:04:16 +00:00
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 ;
2009-04-24 23:35:41 +00:00
}
2012-09-28 21:04:16 +00:00
2018-02-01 22:05:41 +00:00
static inline void GenerateVector ( vvstring & vec , const char * s , const char * prefix , size_t minLength )
2012-09-28 21:04:16 +00:00
{
2019-05-04 18:14:48 +00:00
size_t length = strlen ( s ) ;
2012-09-28 21:04:16 +00:00
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 ;
2019-05-04 18:14:48 +00:00
for ( size_t i = vec . size ( ) ; i < minLength ; + + i )
2012-09-28 21:04:16 +00:00
{
vec . push_back ( emptyVector ) ;
}
delete [ ] temp ;
2009-04-24 23:35:41 +00:00
}
2012-09-28 21:04:16 +00:00
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 ;
2018-02-01 22:05:41 +00:00
while ( * pch ! = ' \0 ' )
2012-09-28 21:04:16 +00:00
{
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 ) ;
}
2009-04-24 23:35:41 +00:00
}
2019-05-04 18:14:48 +00:00
static inline void ReColoringCheck ( Sci_PositionU & startPos , int & nestedLevel , int & initStyle , int & openIndex ,
2012-09-28 21:04:16 +00:00
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 ) ;
2013-01-27 01:03:53 +00:00
2012-09-28 21:04:16 +00:00
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 )
{
2019-05-04 18:14:48 +00:00
if ( iter - > _position > = startPos )
2012-09-28 21:04:16 +00:00
{
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 ( ) ;
2019-05-04 18:14:48 +00:00
while ( iter - > _nestedLevel > 1 & & iter ! = nestedVector . begin ( ) )
2012-09-28 21:04:16 +00:00
- - 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 ( ) )
{
2019-05-04 18:14:48 +00:00
if ( iter - > _opener = = NI_OPEN )
2012-09-28 21:04:16 +00:00
lastNestedGroup . push_back ( * iter ) ;
2019-05-04 18:14:48 +00:00
else if ( iter - > _opener = = NI_CLOSE & & ! lastNestedGroup . empty ( ) )
2012-09-28 21:04:16 +00:00
{
last = - - lastNestedGroup . end ( ) ;
2019-05-04 18:14:48 +00:00
if ( last - > _opener = = NI_OPEN )
if ( last - > _nestedLevel = = iter - > _nestedLevel )
if ( last - > _state = = iter - > _state )
if ( last - > _index = = iter - > _index )
2012-09-28 21:04:16 +00:00
lastNestedGroup . erase ( last ) ;
}
+ + iter ;
}
if ( ! lastNestedGroup . empty ( ) )
{
last = - - lastNestedGroup . end ( ) ;
2019-05-04 18:14:48 +00:00
initStyle = last - > _state ;
openIndex = last - > _index ;
nestedLevel = last - > _nestedLevel ;
2012-09-28 21:04:16 +00:00
// are we nested somewhere in comment?
for ( ; ; - - last )
{
2019-05-04 18:14:48 +00:00
if ( last - > _state = = SCE_USER_STYLE_COMMENT )
2012-09-28 21:04:16 +00:00
{
isInComment = true ;
isCommentLine = COMMENTLINE_YES ;
}
2019-05-04 18:14:48 +00:00
if ( last - > _state = = SCE_USER_STYLE_COMMENTLINE )
2012-09-28 21:04:16 +00:00
{
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());
}
2019-05-04 18:14:48 +00:00
static bool isInListForward ( vvstring & openVector , StyleContext & sc , bool ignoreCase , int & openIndex , size_t & skipForward )
2012-09-28 21:04:16 +00:00
{
// 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 ,
2019-05-04 18:14:48 +00:00
int & moveForward , vvstring * fwEndVectors [ ] , int & nlCount , size_t docLength )
2012-09-28 21:04:16 +00:00
{
// 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
2013-08-28 00:44:27 +00:00
if ( ! list . Length ( ) )
2012-09-28 21:04:16 +00:00
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 ;
2013-08-28 00:44:27 +00:00
int i = list . StartAt ( firstChar ) ;
2012-09-28 21:04:16 +00:00
bool doUpperLoop = ignoreCase ;
if ( ignoreCase )
{
2013-08-28 00:44:27 +00:00
i = list . StartAt ( tolower ( firstChar ) ) ;
2012-09-28 21:04:16 +00:00
if ( i = = - 1 )
{
2013-08-28 00:44:27 +00:00
i = list . StartAt ( toupper ( firstChar ) ) ;
2012-09-28 21:04:16 +00:00
if ( i = = - 1 )
return false ;
doUpperLoop = false ;
}
}
while ( i > = 0 )
{
2013-08-28 00:44:27 +00:00
while ( static_cast < unsigned char > ( ignoreCase ? toupper ( list . WordAt ( i ) [ 0 ] ) : list . WordAt ( i ) [ 0 ] ) = = ( ignoreCase ? toupper ( firstChar ) : firstChar ) )
2012-09-28 21:04:16 +00:00
{
a = 0 ;
b = 0 ;
bNext = 0 ;
indexa = 0 ;
indexb = 0 ;
wsChar = 0 ;
fwDelimiterFound = NO_DELIMITER ;
do
{
2013-08-28 00:44:27 +00:00
a = static_cast < unsigned char > ( ignoreCase ? toupper ( list . WordAt ( i ) [ indexa + + ] ) : list . WordAt ( i ) [ indexa + + ] ) ;
2012-09-28 21:04:16 +00:00
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 ) ) ;
2013-08-28 00:44:27 +00:00
a = static_cast < unsigned char > ( ignoreCase ? toupper ( list . WordAt ( i ) [ indexa + + ] ) : list . WordAt ( i ) [ indexa + + ] ) ;
2012-09-28 21:04:16 +00:00
}
2013-01-27 01:03:53 +00:00
b = ignoreCase ? toupper ( b ) : b ;
2012-09-28 21:04:16 +00:00
}
else
b = ignoreCase ? toupper ( sc . GetRelative ( offset + indexb + + ) ) : sc . GetRelative ( offset + indexb + + ) ;
}
while ( a & & ( a = = b ) ) ;
if ( ! a )
2009-09-10 00:44:36 +00:00
{
2012-09-28 21:04:16 +00:00
- - 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"
2012-10-20 16:20:57 +00:00
bNext = sc . GetRelative ( indexb + offset ) ;
2012-10-07 21:49:52 +00:00
if ( isWhiteSpace ( bNext ) )
2012-09-28 21:04:16 +00:00
fwDelimiterFound = FORWARD_WHITESPACE_FOUND ;
if ( fwDelimiterFound = = NO_DELIMITER )
{
2012-10-20 16:20:57 +00:00
if ( isInListForward2 ( fwEndVectors , FW_VECTORS_TOTAL , sc , ignoreCase , indexb + offset ) )
2012-09-28 21:04:16 +00:00
{
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 ) ) )
{
2012-10-20 16:20:57 +00:00
if ( isInListForward2 ( fwEndVectors , FW_VECTORS_TOTAL , sc , ignoreCase , indexb + offset ) )
2012-09-28 21:04:16 +00:00
{
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
2012-10-20 16:20:57 +00:00
if ( wsChar )
2012-09-28 21:04:16 +00:00
{
2012-10-20 16:20:57 +00:00
if ( fwDelimiterFound ! = NO_DELIMITER )
return true ; // multi part keyword found
2012-09-28 21:04:16 +00:00
}
else if ( moveForward = = 0 )
return true ; // single part keyword found
else if ( specialMode )
return true ; // prefixed single part keyword found
2009-09-10 00:44:36 +00:00
}
2012-09-28 21:04:16 +00:00
nlCountTemp = 0 ;
+ + i ;
}
// run one more time for capital letter version
if ( doUpperLoop )
{
2013-08-28 00:44:27 +00:00
i = list . StartAt ( toupper ( firstChar ) ) ;
2012-09-28 21:04:16 +00:00
doUpperLoop = false ;
}
else
break ;
}
return false ;
}
static void setBackwards ( WordList * kwLists [ ] , StyleContext & sc , bool prefixes [ ] , bool ignoreCase ,
int nestedKey , vvstring * fwEndVectors [ ] , int & levelMinCurrent ,
2019-05-04 18:14:48 +00:00
int & levelNext , int & nlCount , bool & dontMove , size_t docLength )
2012-09-28 21:04:16 +00:00
{
if ( sc . LengthCurrent ( ) = = 0 )
return ;
int folding = FOLD_NONE ;
int moveForward = 0 ;
2016-05-12 20:12:58 +00:00
for ( int i = 0 ; i < MAPPER_TOTAL ; + + i )
2012-09-28 21:04:16 +00:00
{
if ( nestedKey & maskMapper [ i ] )
{
if ( isInListBackward ( * kwLists [ i ] , sc , prefixes [ i ] , ignoreCase , moveForward , fwEndVectors , nlCount , docLength ) )
2009-09-10 00:44:36 +00:00
{
2012-09-28 21:04:16 +00:00
folding = foldingtMapper [ i ] ;
if ( moveForward > 0 )
{
sc . Forward ( moveForward ) ;
dontMove = true ;
}
sc . ChangeState ( styleMapper [ i ] ) ;
break ;
2009-09-10 00:44:36 +00:00
}
2012-09-28 21:04:16 +00:00
}
}
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 ,
2019-05-04 18:14:48 +00:00
bool ignoreCase , int & openIndex , size_t & skipForward , int & newState , int pureLC ,
2013-01-27 01:03:53 +00:00
bool visibleChars , vector < string > * numberTokens [ ] , vvstring * * numberDelims , int decSeparator )
2012-09-28 21:04:16 +00:00
{
// check if some other delimiter is nested within current delimiter
2013-01-27 01:03:53 +00:00
// all delimiters are freely checked but line comments must be synched with property 'pureLC'
2012-09-28 21:04:16 +00:00
int backup = openIndex ;
vector < forwardStruct > : : iterator iter = forwards . begin ( ) ;
for ( ; iter ! = forwards . end ( ) ; + + iter )
{
2019-05-04 18:14:48 +00:00
if ( nestedKey & iter - > _maskID )
2012-09-28 21:04:16 +00:00
{
2019-05-04 18:14:48 +00:00
if ( ( iter - > _maskID ! = SCE_USER_MASK_NESTING_COMMENT_LINE ) | |
( iter - > _maskID = = SCE_USER_MASK_NESTING_COMMENT_LINE & &
2013-01-27 01:03:53 +00:00
( ( pureLC = = PURE_LC_NONE ) | |
( pureLC = = PURE_LC_BOL & & ( sc . chPrev = = ' \r ' | | sc . chPrev = = ' \n ' ) ) | |
( pureLC = = PURE_LC_WSP & & visibleChars = = false ) ) ) )
2009-09-10 00:44:36 +00:00
{
2019-05-04 18:14:48 +00:00
if ( isInListForward ( * ( iter - > _vec ) , sc , ignoreCase , openIndex , skipForward ) )
2012-09-28 21:04:16 +00:00
{
2019-05-04 18:14:48 +00:00
newState = iter - > _sceID ;
2012-09-28 21:04:16 +00:00
return true ;
}
2009-09-10 00:44:36 +00:00
}
2012-09-28 21:04:16 +00:00
}
}
2009-04-24 23:35:41 +00:00
2012-10-20 16:20:57 +00:00
if ( nestedKey & SCE_USER_MASK_NESTING_NUMBERS )
{
if ( IsNumber ( sc , numberTokens , numberDelims , ignoreCase , decSeparator , skipForward ) )
{
newState = SCE_USER_STYLE_NUMBER ;
return true ;
}
}
2012-09-28 21:04:16 +00:00
openIndex = backup ;
return false ;
2009-04-24 23:35:41 +00:00
}
2012-09-28 21:04:16 +00:00
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 ( ) )
{
2019-05-04 18:14:48 +00:00
newState = ( - - lastNestedGroup . end ( ) ) - > _state ;
openIndex = ( - - lastNestedGroup . end ( ) ) - > _index ;
2012-09-28 21:04:16 +00:00
}
}
}
2009-04-24 23:35:41 +00:00
2019-05-04 18:14:48 +00:00
static void ColouriseUserDoc ( Sci_PositionU startPos , Sci_Position length , int initStyle , WordList * kwLists [ ] , Accessor & styler )
2009-04-24 23:35:41 +00:00
{
2013-01-27 01:03:53 +00:00
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 ) ;
2012-09-28 21:04:16 +00:00
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 ;
2013-01-27 01:03:53 +00:00
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 ;
2012-09-28 21:04:16 +00:00
vector < string > & rangeTokens = udlKeywordsMap [ sUdlName ] . rangeTokens ;
2012-10-20 16:20:57 +00:00
vector < string > & negativePrefixTokens1 = udlKeywordsMap [ sUdlName ] . negativePrefixTokens1 ;
vector < string > & negativePrefixTokens2 = udlKeywordsMap [ sUdlName ] . negativePrefixTokens2 ;
2013-01-27 01:03:53 +00:00
vector < string > & negativeExtrasTokens2 = udlKeywordsMap [ sUdlName ] . negativeExtrasTokens2 ;
2012-09-28 21:04:16 +00:00
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
{
2013-08-28 00:44:27 +00:00
for ( int j = 0 ; j < kwLists [ i ] - > Length ( ) ; + + j ) // for each keyword within object
2012-09-28 21:04:16 +00:00
{
equal = true ;
int z = 0 ;
2013-08-28 00:44:27 +00:00
for ( ; kwLists [ i ] - > WordAt ( j ) [ z ] ; + + z ) // for each letter within keyword
2012-09-28 21:04:16 +00:00
{
2013-08-28 00:44:27 +00:00
if ( kwLists [ i ] - > WordAt ( j + 1 ) [ z ] = = ' \v ' | | kwLists [ i ] - > WordAt ( j + 1 ) [ z ] = = ' \b ' )
2012-09-28 21:04:16 +00:00
isMultiPart = true ;
2013-08-28 00:44:27 +00:00
if ( kwLists [ i ] - > WordAt ( j ) [ z ] ! = kwLists [ i ] - > WordAt ( j + 1 ) [ z ] )
2012-09-28 21:04:16 +00:00
{
equal = false ;
break ;
}
}
if ( ! isMultiPart ) // is next word multi part keyword?
{
2013-08-28 00:44:27 +00:00
for ( int k = 0 ; kwLists [ i ] - > WordAt ( j + 1 ) [ k ] ; + + k )
2012-09-28 21:04:16 +00:00
{
2013-08-28 00:44:27 +00:00
if ( kwLists [ i ] - > WordAt ( j + 1 ) [ k ] = = ' \v ' | | kwLists [ i ] - > WordAt ( j + 1 ) [ k ] = = ' \b ' )
2012-09-28 21:04:16 +00:00
{
isMultiPart = true ;
break ;
}
}
}
2013-08-28 00:44:27 +00:00
if ( equal & & isMultiPart & & kwLists [ i ] - > WordAt ( j + 1 ) [ z ] ) // perform switch only if next word is longer !
2012-09-28 21:04:16 +00:00
{
2013-08-28 00:44:27 +00:00
const char * temp = kwLists [ i ] - > WordAt ( j ) ;
kwLists [ i ] - > SetWordAt ( j , kwLists [ i ] - > WordAt ( j + 1 ) ) ;
kwLists [ i ] - > SetWordAt ( j + 1 , temp ) ;
2012-09-28 21:04:16 +00:00
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
2015-06-11 08:10:19 +00:00
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 ( ) ) ;
2012-09-28 21:04:16 +00:00
operators1 . clear ( ) ;
foldersInCode1Open . clear ( ) ;
foldersInCode1Middle . clear ( ) ;
foldersInCode1Close . clear ( ) ;
SubGroup ( sFoldersInCode1Open , foldersInCode1Open , true ) ;
SubGroup ( sFoldersInCode1Middle , foldersInCode1Middle , true ) ;
SubGroup ( sFoldersInCode1Close , foldersInCode1Close , true ) ;
SubGroup ( sOperators1 , operators1 , true ) ;
2013-01-27 01:03:53 +00:00
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 " ) ;
2012-09-28 21:04:16 +00:00
2013-01-27 01:03:53 +00:00
prefixTokens1 . clear ( ) ;
2012-10-20 16:20:57 +00:00
prefixTokens2 . clear ( ) ;
2013-01-27 01:03:53 +00:00
extrasTokens1 . clear ( ) ;
extrasTokens2 . clear ( ) ;
suffixTokens1 . clear ( ) ;
suffixTokens2 . clear ( ) ;
2012-09-28 21:04:16 +00:00
rangeTokens . clear ( ) ;
2013-01-27 01:03:53 +00:00
negativePrefixTokens1 . clear ( ) ;
negativePrefixTokens2 . clear ( ) ;
negativeExtrasTokens2 . clear ( ) ;
2012-09-28 21:04:16 +00:00
// 'StringToVector' converts strings into vector<string> objects
2013-01-27 01:03:53 +00:00
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 ) ;
2012-09-28 21:04:16 +00:00
}
// 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 ;
2013-01-27 01:03:53 +00:00
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 ;
2012-09-28 21:04:16 +00:00
// keep delimiter escape/close strings in an array for easier looping
2012-10-20 16:20:57 +00:00
vvstring * delimVectors [ ( SCE_USER_TOTAL_DELIMITERS + 2 ) * 2 ] ;
2012-09-28 21:04:16 +00:00
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 ;
2012-10-20 16:20:57 +00:00
// 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 ;
2012-09-28 21:04:16 +00:00
// again, loops make our lifes easier
2012-10-20 16:20:57 +00:00
int delimNestings [ SCE_USER_TOTAL_DELIMITERS + 2 ] ;
2012-09-28 21:04:16 +00:00
delimNestings [ 0 ] = delim1Nesting ;
delimNestings [ 1 ] = delim2Nesting ;
delimNestings [ 2 ] = delim3Nesting ;
delimNestings [ 3 ] = delim4Nesting ;
delimNestings [ 4 ] = delim5Nesting ;
delimNestings [ 5 ] = delim6Nesting ;
delimNestings [ 6 ] = delim7Nesting ;
delimNestings [ 7 ] = delim8Nesting ;
2012-10-20 16:20:57 +00:00
// 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 ;
}
2013-01-27 01:03:53 +00:00
vector < string > * numberTokens [ 10 ] ;
2012-10-20 16:20:57 +00:00
numberTokens [ 0 ] = & prefixTokens1 ;
numberTokens [ 1 ] = & prefixTokens2 ;
2013-01-27 01:03:53 +00:00
numberTokens [ 2 ] = & extrasTokens1 ;
numberTokens [ 3 ] = & extrasTokens2 ;
numberTokens [ 4 ] = & suffixTokens1 ;
numberTokens [ 5 ] = & suffixTokens2 ;
numberTokens [ 6 ] = & rangeTokens ;
numberTokens [ 7 ] = & negativePrefixTokens1 ;
numberTokens [ 8 ] = & negativePrefixTokens2 ;
numberTokens [ 9 ] = & negativeExtrasTokens2 ;
2012-09-28 21:04:16 +00:00
int levelCurrent = SC_FOLDLEVELBASE ;
2012-10-20 16:20:57 +00:00
int lineCurrent = 0 ;
2012-09-28 21:04:16 +00:00
int levelMinCurrent = 0 ;
int levelNext = 0 ;
int levelPrev = 0 ;
int lev = 0 ;
bool visibleChars = false ;
2013-01-27 01:03:53 +00:00
bool skipVisibleCheck = false ;
2012-09-28 21:04:16 +00:00
bool dontMove = false ;
bool finished = true ;
2013-01-27 01:03:53 +00:00
int checkEOL = EOL_DEFAULT_VALUE ;
2012-09-28 21:04:16 +00:00
2019-05-04 18:14:48 +00:00
int nestedLevel = 0 ;
2012-09-28 21:04:16 +00:00
int openIndex = 0 ;
2019-05-04 18:14:48 +00:00
size_t skipForward = 0 ;
2012-09-28 21:04:16 +00:00
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 ;
2012-10-20 16:20:57 +00:00
int decSeparator = SEPARATOR_DOT ;
2012-09-28 21:04:16 +00:00
vector < nestedInfo > lastNestedGroup ;
vvstring * delimEscape = NULL ;
vvstring * delimClose = NULL ;
2012-10-20 16:20:57 +00:00
vvstring * * numberDelims = NULL ;
2012-09-28 21:04:16 +00:00
int delimNesting = 0 ;
2019-05-04 18:14:48 +00:00
size_t docLength = startPos + length ;
2012-09-28 21:04:16 +00:00
if ( startPos = = 0 )
{
// foldVector.clear();
nestedVector . clear ( ) ;
lastNestedGroup . clear ( ) ;
initStyle = SCE_USER_STYLE_IDENTIFIER ;
}
else
{
2019-05-04 18:14:48 +00:00
size_t oldStartPos = startPos ;
2012-09-28 21:04:16 +00:00
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 ) ;
2015-07-02 22:25:38 +00:00
for ( ; finished ; )
2012-09-28 21:04:16 +00:00
{
dontMove = false ;
2013-01-27 01:03:53 +00:00
checkEOL = EOL_DEFAULT_VALUE ;
2012-09-28 21:04:16 +00:00
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 ] ;
2012-10-20 16:20:57 +00:00
numberDelims = numberDelimSeparators [ index ] ;
2012-09-28 21:04:16 +00:00
prevState = sc . state ;
newState = sc . state ;
// first, check escape sequence
2012-10-20 16:20:57 +00:00
bool loopEscape = true ;
vector < string > : : iterator iter ;
while ( loopEscape = = true )
2012-09-28 21:04:16 +00:00
{
2012-10-20 16:20:57 +00:00
loopEscape = false ;
iter = ( * delimEscape ) [ openIndex ] . begin ( ) ;
for ( ; iter ! = ( * delimEscape ) [ openIndex ] . end ( ) ; + + iter )
2012-09-28 21:04:16 +00:00
{
2012-10-20 16:20:57 +00:00
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;
}
2012-09-28 21:04:16 +00:00
}
}
// 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 ( ) ) ;
2013-01-27 01:03:53 +00:00
if ( sc . atLineStart )
checkEOL = EOL_FORCE_CHECK ;
2012-09-28 21:04:16 +00:00
// 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 ) ;
}
2012-10-20 16:20:57 +00:00
else if ( ( ! isWhiteSpace ( sc . ch ) & & isWhiteSpace ( sc . chPrev ) ) )
2012-09-28 21:04:16 +00:00
{
// create new 'compare point' (AKA beginning of nested keyword) before checking for numbers
sc . SetState ( prevState ) ;
}
// third, check nested delimiter sequence
2013-01-27 01:03:53 +00:00
if ( isInListNested ( delimNesting , forwards , sc , ignoreCase , openIndex , skipForward ,
newState , pureLC , visibleChars , numberTokens , numberDelims , decSeparator ) )
2012-09-28 21:04:16 +00:00
{
// any backward keyword 'glued' on the left side?
setBackwards ( kwLists , sc , prefixes , ignoreCase , delimNesting , fwEndVectors , levelMinCurrent , levelNext , nlCount , dontMove , docLength ) ;
2012-10-20 16:20:57 +00:00
if ( newState ! = SCE_USER_STYLE_OPERATOR & & newState ! = SCE_USER_STYLE_NUMBER )
2012-09-28 21:04:16 +00:00
{
// 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 ) ;
2012-10-20 16:20:57 +00:00
if ( newState = = SCE_USER_STYLE_OPERATOR | | newState = = SCE_USER_STYLE_NUMBER )
2012-09-28 21:04:16 +00:00
sc . ChangeState ( prevState ) ;
2012-10-20 16:20:57 +00:00
2012-09-28 21:04:16 +00:00
dontMove = true ;
break ;
}
break ;
}
case SCE_USER_STYLE_COMMENT :
{
2012-10-20 16:20:57 +00:00
numberDelims = numberDelimSeparators [ SCE_USER_TOTAL_DELIMITERS ] ;
2012-09-28 21:04:16 +00:00
// 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
2013-01-27 01:03:53 +00:00
if ( isInListNested ( commentNesting , forwards , sc , ignoreCase , openIndex , skipForward ,
newState , pureLC , visibleChars , numberTokens , numberDelims , decSeparator ) )
2012-09-28 21:04:16 +00:00
{
// any backward keyword 'glued' on the left side?
setBackwards ( kwLists , sc , prefixes , ignoreCase , commentNesting , fwEndVectors , levelMinCurrent , levelNext , nlCount , dontMove , docLength ) ;
2012-10-20 16:20:57 +00:00
if ( newState ! = SCE_USER_STYLE_OPERATOR & & newState ! = SCE_USER_STYLE_NUMBER )
2012-09-28 21:04:16 +00:00
{
// 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 ) ;
2012-10-20 16:20:57 +00:00
if ( newState = = SCE_USER_STYLE_OPERATOR | | newState = = SCE_USER_STYLE_NUMBER )
2012-09-28 21:04:16 +00:00
sc . ChangeState ( SCE_USER_STYLE_COMMENT ) ;
2012-10-20 16:20:57 +00:00
2012-09-28 21:04:16 +00:00
dontMove = true ;
break ;
}
break ;
}
case SCE_USER_STYLE_COMMENTLINE :
{
2012-10-20 16:20:57 +00:00
numberDelims = numberDelimSeparators [ SCE_USER_TOTAL_DELIMITERS + 1 ] ;
2012-09-28 21:04:16 +00:00
// 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 ;
2013-01-27 01:03:53 +00:00
break ; // break out of 'for', not 'case'
2012-09-28 21:04:16 +00:00
}
}
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 )
{
2019-05-04 18:14:48 +00:00
size_t length = iter - > length ( ) ;
2012-09-28 21:04:16 +00:00
if ( length = = 0 )
2015-07-02 22:25:38 +00:00
{
if ( ! dontMove )
sc . Forward ( ) ;
2012-09-28 21:04:16 +00:00
continue ;
2015-07-02 22:25:38 +00:00
}
2012-09-28 21:04:16 +00:00
lineContinuation = true ;
2019-05-04 18:14:48 +00:00
for ( size_t i = 0 ; i < length ; + + i )
2012-09-28 21:04:16 +00:00
{
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 )
{
2013-01-27 01:03:53 +00:00
// paint \n character too (or \r for old MAc format)
sc . Forward ( ) ;
dontMove = true ;
checkEOL = EOL_FORCE_CHECK ;
2012-09-28 21:04:16 +00:00
// 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
2013-01-27 01:03:53 +00:00
if ( isInListNested ( lineCommentNesting , forwards , sc , ignoreCase , openIndex , skipForward ,
newState , pureLC , visibleChars , numberTokens , numberDelims , decSeparator ) )
2012-09-28 21:04:16 +00:00
{
// any backward keyword 'glued' on the left side?
setBackwards ( kwLists , sc , prefixes , ignoreCase , lineCommentNesting , fwEndVectors , levelMinCurrent , levelNext , nlCount , dontMove , docLength ) ;
2012-10-20 16:20:57 +00:00
if ( newState ! = SCE_USER_STYLE_OPERATOR & & newState ! = SCE_USER_STYLE_NUMBER )
2012-09-28 21:04:16 +00:00
{
// 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 ) ;
2012-10-20 16:20:57 +00:00
if ( newState = = SCE_USER_STYLE_OPERATOR | | newState = = SCE_USER_STYLE_NUMBER )
2012-09-28 21:04:16 +00:00
sc . ChangeState ( SCE_USER_STYLE_COMMENTLINE ) ;
2012-10-20 16:20:57 +00:00
2012-09-28 21:04:16 +00:00
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 ( ) )
{
2013-01-27 01:03:53 +00:00
if ( ( pureLC = = PURE_LC_NONE ) | |
( pureLC = = PURE_LC_BOL & & ( sc . chPrev = = ' \r ' | | sc . chPrev = = ' \n ' ) ) | |
( pureLC = = PURE_LC_WSP & & visibleChars = = false ) )
2012-09-28 21:04:16 +00:00
{
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 ;
2013-01-27 01:03:53 +00:00
if ( sc . atLineEnd )
checkEOL = EOL_SKIP_CHECK ;
2020-05-10 03:19:08 +00:00
2012-09-28 21:04:16 +00:00
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 ;
2013-01-27 01:03:53 +00:00
if ( sc . atLineEnd )
checkEOL = EOL_SKIP_CHECK ;
2020-05-10 03:19:08 +00:00
2012-09-28 21:04:16 +00:00
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 ;
2013-01-27 01:03:53 +00:00
if ( sc . atLineEnd )
checkEOL = EOL_SKIP_CHECK ;
2012-09-28 21:04:16 +00:00
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 ) ;
2012-10-20 16:20:57 +00:00
//sc.ChangeState(SCE_USER_STYLE_OPERATOR);
2012-09-28 21:04:16 +00:00
// no closing sequence, start over from default
sc . SetState ( SCE_USER_STYLE_IDENTIFIER ) ;
dontMove = true ;
2017-06-06 21:12:28 +00:00
if ( sc . atLineEnd )
checkEOL = EOL_SKIP_CHECK ;
2012-09-28 21:04:16 +00:00
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 ) ;
2012-10-20 16:20:57 +00:00
//sc.ChangeState(SCE_USER_STYLE_FOLDER_IN_CODE1);
2012-09-28 21:04:16 +00:00
// no closing sequence, start over from default
sc . SetState ( SCE_USER_STYLE_IDENTIFIER ) ;
dontMove = true ;
2013-01-27 01:03:53 +00:00
if ( sc . atLineEnd )
checkEOL = EOL_SKIP_CHECK ;
2012-09-28 21:04:16 +00:00
if ( levelMinCurrent > levelNext )
levelMinCurrent = levelNext ;
2013-01-27 01:03:53 +00:00
2012-09-28 21:04:16 +00:00
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 ) ;
2012-10-20 16:20:57 +00:00
//sc.ChangeState(SCE_USER_STYLE_FOLDER_IN_CODE1);
2012-09-28 21:04:16 +00:00
// no closing sequence, start over from default
sc . SetState ( SCE_USER_STYLE_IDENTIFIER ) ;
dontMove = true ;
2013-01-27 01:03:53 +00:00
if ( sc . atLineEnd )
2017-06-06 21:12:28 +00:00
checkEOL = EOL_SKIP_CHECK ;
2013-01-27 01:03:53 +00:00
2012-09-28 21:04:16 +00:00
levelNext - - ;
if ( levelMinCurrent > levelNext )
levelMinCurrent = levelNext ;
2013-01-27 01:03:53 +00:00
2012-09-28 21:04:16 +00:00
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 ) ;
2012-10-20 16:20:57 +00:00
//sc.ChangeState(SCE_USER_STYLE_FOLDER_IN_CODE1);
2012-09-28 21:04:16 +00:00
// no closing sequence, start over from default
sc . SetState ( SCE_USER_STYLE_IDENTIFIER ) ;
2013-01-27 01:03:53 +00:00
if ( sc . atLineEnd )
2017-06-06 21:12:28 +00:00
checkEOL = EOL_SKIP_CHECK ;
2013-01-27 01:03:53 +00:00
2012-09-28 21:04:16 +00:00
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 :
{
2012-10-20 16:20:57 +00:00
if ( isWhiteSpace ( sc . ch ) )
2012-09-28 21:04:16 +00:00
break ;
2012-10-20 16:20:57 +00:00
if ( IsNumber ( sc , numberTokens , fwEndVectors , ignoreCase , decSeparator , skipForward ) )
2012-09-28 21:04:16 +00:00
{
2012-10-20 16:20:57 +00:00
// 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 ;
2012-09-28 21:04:16 +00:00
}
if ( ! isWhiteSpace ( sc . ch ) ) // && isWhiteSpace(sc.chPrev)) // word start
{
sc . SetState ( SCE_USER_STYLE_DEFAULT ) ;
2013-01-27 01:03:53 +00:00
skipVisibleCheck = true ;
2012-09-28 21:04:16 +00:00
dontMove = true ;
break ;
}
break ;
}
default :
break ;
}
2013-01-27 01:03:53 +00:00
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 ;
}
}
2015-07-02 22:25:38 +00:00
if ( ! dontMove )
sc . Forward ( ) ;
2012-09-28 21:04:16 +00:00
}
sc . Complete ( ) ;
2009-04-24 23:35:41 +00:00
}
2019-05-04 18:14:48 +00:00
static void FoldUserDoc ( Sci_PositionU /* startPos */ , Sci_Position /* length */ , int /*initStyle*/ , WordList * [ ] , Accessor & /* styler */ )
2012-09-28 21:04:16 +00:00
{
// 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;
2009-04-24 23:35:41 +00:00
2012-09-28 21:04:16 +00:00
// for (; iter != foldVectorStatic->end(); ++iter)
// {
// styler.SetLevel(lineCurrent++, *iter);
// }
}
2009-04-24 23:35:41 +00:00
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 ) ;