601 lines
20 KiB
C++
601 lines
20 KiB
C++
|
// Scintilla source code edit control
|
||
|
// @file LexPowerPro.cxx
|
||
|
// PowerPro utility, written by Bruce Switzer, is available from http://powerpro.webeddie.com
|
||
|
// PowerPro lexer is written by Christopher Bean (cbean@cb-software.net)
|
||
|
//
|
||
|
// Lexer code heavily borrowed from:
|
||
|
// LexAU3.cxx by Jos van der Zande
|
||
|
// LexCPP.cxx by Neil Hodgson
|
||
|
// LexVB.cxx by Neil Hodgson
|
||
|
//
|
||
|
// Changes:
|
||
|
// 2008-10-25 - Initial release
|
||
|
// 2008-10-26 - Changed how <name> is hilighted in 'function <name>' so that
|
||
|
// local isFunction = "" and local functions = "" don't get falsely highlighted
|
||
|
// 2008-12-14 - Added bounds checking for szKeyword and szDo
|
||
|
// - Replaced SetOfCharacters with CharacterSet
|
||
|
// - Made sure that CharacterSet::Contains is passed only positive values
|
||
|
// - Made sure that the return value of Accessor::SafeGetCharAt is positive before
|
||
|
// passsing to functions that require positive values like isspacechar()
|
||
|
// - Removed unused visibleChars processing from ColourisePowerProDoc()
|
||
|
// - Fixed bug with folding logic where line continuations didn't end where
|
||
|
// they were supposed to
|
||
|
// - Moved all helper functions to the top of the file
|
||
|
//
|
||
|
// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
|
||
|
// The License.txt file describes the conditions under which this software may be distributed.
|
||
|
|
||
|
#include <ctype.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "Platform.h"
|
||
|
#include "PropSet.h"
|
||
|
#include "Accessor.h"
|
||
|
#include "StyleContext.h"
|
||
|
#include "KeyWords.h"
|
||
|
#include "Scintilla.h"
|
||
|
#include "SciLexer.h"
|
||
|
#include "CharacterSet.h"
|
||
|
|
||
|
#ifdef SCI_NAMESPACE
|
||
|
using namespace Scintilla;
|
||
|
#endif
|
||
|
|
||
|
static inline bool IsStreamCommentStyle(int style) {
|
||
|
return style == SCE_POWERPRO_COMMENTBLOCK;
|
||
|
}
|
||
|
|
||
|
static bool IsContinuationLine(unsigned int szLine, Accessor &styler)
|
||
|
{
|
||
|
int nsPos = styler.LineStart(szLine);
|
||
|
int nePos = styler.LineStart(szLine + 1) - 2;
|
||
|
while (nsPos < nePos)
|
||
|
{
|
||
|
int stylech = styler.StyleAt(nsPos);
|
||
|
if (!(stylech == SCE_POWERPRO_COMMENTBLOCK)) {
|
||
|
char ch = styler.SafeGetCharAt(nePos);
|
||
|
char chPrev = styler.SafeGetCharAt(nePos-1);
|
||
|
char chPrevPrev = styler.SafeGetCharAt(nePos-2);
|
||
|
if (ch > 0 && chPrev > 0 && chPrevPrev > 0 && !isspacechar(ch) && !isspacechar(chPrev) && !isspacechar(chPrevPrev) ) {
|
||
|
if (chPrevPrev == ';' && chPrev == ';' && ch == '+')
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
nePos--; // skip to next char
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Routine to find first none space on the current line and return its Style
|
||
|
// needed for comment lines not starting on pos 1
|
||
|
static int GetStyleFirstWord(unsigned int szLine, Accessor &styler)
|
||
|
{
|
||
|
int nsPos = styler.LineStart(szLine);
|
||
|
int nePos = styler.LineStart(szLine+1) - 1;
|
||
|
char ch = styler.SafeGetCharAt(nsPos);
|
||
|
|
||
|
while (ch > 0 && isspacechar(ch) && nsPos < nePos)
|
||
|
{
|
||
|
nsPos++; // skip to next char
|
||
|
ch = styler.SafeGetCharAt(nsPos);
|
||
|
|
||
|
}
|
||
|
return styler.StyleAt(nsPos);
|
||
|
}
|
||
|
|
||
|
//returns true if there is a function to highlight
|
||
|
//used to highlight <name> in 'function <name>'
|
||
|
static bool HasFunction(Accessor &styler, unsigned int currentPos) {
|
||
|
|
||
|
//check for presence of 'function '
|
||
|
return (styler.SafeGetCharAt(currentPos) == ' '
|
||
|
&& tolower(styler.SafeGetCharAt(currentPos-1)) == 'n'
|
||
|
&& tolower(styler.SafeGetCharAt(currentPos-2)) == 'o'
|
||
|
&& tolower(styler.SafeGetCharAt(currentPos-3)) == 'i'
|
||
|
&& tolower(styler.SafeGetCharAt(currentPos-4)) == 't'
|
||
|
&& tolower(styler.SafeGetCharAt(currentPos-5)) == 'c'
|
||
|
&& tolower(styler.SafeGetCharAt(currentPos-6)) == 'n'
|
||
|
&& tolower(styler.SafeGetCharAt(currentPos-7)) == 'u'
|
||
|
&& tolower(styler.SafeGetCharAt(currentPos-8)) == 'f'
|
||
|
//only allow 'function ' to appear at the beginning of a line
|
||
|
&& (styler.SafeGetCharAt(currentPos-9) == '\n'
|
||
|
|| styler.SafeGetCharAt(currentPos-9) == '\r'
|
||
|
|| (styler.SafeGetCharAt(currentPos -9, '\0')) == '\0') //is the first line
|
||
|
);
|
||
|
}
|
||
|
|
||
|
static void ColourisePowerProDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
|
||
|
Accessor &styler, bool caseSensitive) {
|
||
|
|
||
|
WordList &keywords = *keywordlists[0];
|
||
|
WordList &keywords2 = *keywordlists[1];
|
||
|
WordList &keywords3 = *keywordlists[2];
|
||
|
WordList &keywords4 = *keywordlists[3];
|
||
|
|
||
|
//define the character sets
|
||
|
CharacterSet setWordStart(CharacterSet::setAlpha, "_@", 0x80, true);
|
||
|
CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true);
|
||
|
|
||
|
StyleContext sc(startPos, length, initStyle, styler);
|
||
|
char s_save[100]; //for last line highlighting
|
||
|
|
||
|
for (; sc.More(); sc.Forward()) {
|
||
|
|
||
|
// **********************************************
|
||
|
// save the total current word for eof processing
|
||
|
char s[100];
|
||
|
sc.GetCurrentLowered(s, sizeof(s));
|
||
|
|
||
|
if ((sc.ch > 0) && setWord.Contains(sc.ch))
|
||
|
{
|
||
|
strcpy(s_save,s);
|
||
|
int tp = strlen(s_save);
|
||
|
if (tp < 99) {
|
||
|
s_save[tp] = static_cast<char>(tolower(sc.ch));
|
||
|
s_save[tp+1] = '\0';
|
||
|
}
|
||
|
}
|
||
|
// **********************************************
|
||
|
//
|
||
|
|
||
|
if (sc.atLineStart) {
|
||
|
if (sc.state == SCE_POWERPRO_DOUBLEQUOTEDSTRING) {
|
||
|
// Prevent SCE_POWERPRO_STRINGEOL from leaking back to previous line which
|
||
|
// ends with a line continuation by locking in the state upto this position.
|
||
|
sc.SetState(SCE_POWERPRO_DOUBLEQUOTEDSTRING);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Determine if the current state should terminate.
|
||
|
switch (sc.state) {
|
||
|
case SCE_POWERPRO_OPERATOR:
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
break;
|
||
|
|
||
|
case SCE_POWERPRO_NUMBER:
|
||
|
|
||
|
if (!IsADigit(sc.ch))
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case SCE_POWERPRO_IDENTIFIER:
|
||
|
//if ((sc.ch > 0) && !setWord.Contains(sc.ch) || (sc.ch == '.')) { // use this line if don't want to match keywords with . in them. ie: win.debug will match both win and debug so win debug will also be colorized
|
||
|
if ((sc.ch > 0) && !setWord.Contains(sc.ch)){ // || (sc.ch == '.')) { // use this line if you want to match keywords with a . ie: win.debug will only match win.debug neither win nor debug will be colorized separately
|
||
|
char s[1000];
|
||
|
if (caseSensitive) {
|
||
|
sc.GetCurrent(s, sizeof(s));
|
||
|
} else {
|
||
|
sc.GetCurrentLowered(s, sizeof(s));
|
||
|
}
|
||
|
if (keywords.InList(s)) {
|
||
|
sc.ChangeState(SCE_POWERPRO_WORD);
|
||
|
} else if (keywords2.InList(s)) {
|
||
|
sc.ChangeState(SCE_POWERPRO_WORD2);
|
||
|
} else if (keywords3.InList(s)) {
|
||
|
sc.ChangeState(SCE_POWERPRO_WORD3);
|
||
|
} else if (keywords4.InList(s)) {
|
||
|
sc.ChangeState(SCE_POWERPRO_WORD4);
|
||
|
}
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_POWERPRO_LINECONTINUE:
|
||
|
if (sc.atLineStart) {
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
} else if (sc.Match('/', '*') || sc.Match('/', '/')) {
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_POWERPRO_COMMENTBLOCK:
|
||
|
if (sc.Match('*', '/')) {
|
||
|
sc.Forward();
|
||
|
sc.ForwardSetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_POWERPRO_COMMENTLINE:
|
||
|
if (sc.atLineStart) {
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_POWERPRO_DOUBLEQUOTEDSTRING:
|
||
|
if (sc.atLineEnd) {
|
||
|
sc.ChangeState(SCE_POWERPRO_STRINGEOL);
|
||
|
} else if (sc.ch == '\\') {
|
||
|
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
|
||
|
sc.Forward();
|
||
|
}
|
||
|
} else if (sc.ch == '\"') {
|
||
|
sc.ForwardSetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_POWERPRO_SINGLEQUOTEDSTRING:
|
||
|
if (sc.atLineEnd) {
|
||
|
sc.ChangeState(SCE_POWERPRO_STRINGEOL);
|
||
|
} else if (sc.ch == '\\') {
|
||
|
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
|
||
|
sc.Forward();
|
||
|
}
|
||
|
} else if (sc.ch == '\'') {
|
||
|
sc.ForwardSetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_POWERPRO_STRINGEOL:
|
||
|
if (sc.atLineStart) {
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_POWERPRO_VERBATIM:
|
||
|
if (sc.ch == '\"') {
|
||
|
if (sc.chNext == '\"') {
|
||
|
sc.Forward();
|
||
|
} else {
|
||
|
sc.ForwardSetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_POWERPRO_ALTQUOTE:
|
||
|
if (sc.ch == '#') {
|
||
|
if (sc.chNext == '#') {
|
||
|
sc.Forward();
|
||
|
} else {
|
||
|
sc.ForwardSetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_POWERPRO_FUNCTION:
|
||
|
if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ' ' || sc.ch == '(') {
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Determine if a new state should be entered.
|
||
|
if (sc.state == SCE_POWERPRO_DEFAULT) {
|
||
|
if (sc.Match('?', '\"')) {
|
||
|
sc.SetState(SCE_POWERPRO_VERBATIM);
|
||
|
sc.Forward();
|
||
|
} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
|
||
|
sc.SetState(SCE_POWERPRO_NUMBER);
|
||
|
}else if (sc.Match('?','#')) {
|
||
|
if (sc.ch == '?' && sc.chNext == '#') {
|
||
|
sc.SetState(SCE_POWERPRO_ALTQUOTE);
|
||
|
sc.Forward();
|
||
|
}
|
||
|
} else if (HasFunction(styler, sc.currentPos)) { //highlight <name> in 'function <name>'
|
||
|
sc.SetState(SCE_POWERPRO_FUNCTION);
|
||
|
} else if (sc.ch == '@' && sc.atLineStart) { //alternate function definition [label]
|
||
|
sc.SetState(SCE_POWERPRO_FUNCTION);
|
||
|
} else if ((sc.ch > 0) && (setWordStart.Contains(sc.ch) || (sc.ch == '?'))) {
|
||
|
sc.SetState(SCE_POWERPRO_IDENTIFIER);
|
||
|
} else if (sc.Match(";;+")) {
|
||
|
sc.SetState(SCE_POWERPRO_LINECONTINUE);
|
||
|
} else if (sc.Match('/', '*')) {
|
||
|
sc.SetState(SCE_POWERPRO_COMMENTBLOCK);
|
||
|
sc.Forward(); // Eat the * so it isn't used for the end of the comment
|
||
|
} else if (sc.Match('/', '/')) {
|
||
|
sc.SetState(SCE_POWERPRO_COMMENTLINE);
|
||
|
} else if (sc.atLineStart && sc.ch == ';') { //legacy comment that can only appear at the beginning of a line
|
||
|
sc.SetState(SCE_POWERPRO_COMMENTLINE);
|
||
|
} else if (sc.Match(";;")) {
|
||
|
sc.SetState(SCE_POWERPRO_COMMENTLINE);
|
||
|
} else if (sc.ch == '\"') {
|
||
|
sc.SetState(SCE_POWERPRO_DOUBLEQUOTEDSTRING);
|
||
|
} else if (sc.ch == '\'') {
|
||
|
sc.SetState(SCE_POWERPRO_SINGLEQUOTEDSTRING);
|
||
|
} else if (isoperator(static_cast<char>(sc.ch))) {
|
||
|
sc.SetState(SCE_POWERPRO_OPERATOR);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//*************************************
|
||
|
// Colourize the last word correctly
|
||
|
//*************************************
|
||
|
if (sc.state == SCE_POWERPRO_IDENTIFIER)
|
||
|
{
|
||
|
if (keywords.InList(s_save)) {
|
||
|
sc.ChangeState(SCE_POWERPRO_WORD);
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
else if (keywords2.InList(s_save)) {
|
||
|
sc.ChangeState(SCE_POWERPRO_WORD2);
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
else if (keywords3.InList(s_save)) {
|
||
|
sc.ChangeState(SCE_POWERPRO_WORD3);
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
else if (keywords4.InList(s_save)) {
|
||
|
sc.ChangeState(SCE_POWERPRO_WORD4);
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
else {
|
||
|
sc.SetState(SCE_POWERPRO_DEFAULT);
|
||
|
}
|
||
|
}
|
||
|
sc.Complete();
|
||
|
}
|
||
|
|
||
|
static void FoldPowerProDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler)
|
||
|
{
|
||
|
//define the character sets
|
||
|
CharacterSet setWordStart(CharacterSet::setAlpha, "_@", 0x80, true);
|
||
|
CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true);
|
||
|
|
||
|
bool isFoldingAll = true; //used to tell if we're recursively folding the whole document, or just a small piece (ie: if statement or 1 function)
|
||
|
int endPos = startPos + length;
|
||
|
int lastLine = styler.GetLine(styler.Length()); //used to help fold the last line correctly
|
||
|
|
||
|
// get settings from the config files for folding comments and preprocessor lines
|
||
|
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
|
||
|
bool foldInComment = styler.GetPropertyInt("fold.comment") == 2;
|
||
|
bool foldCompact = true;
|
||
|
|
||
|
// Backtrack to previous line in case need to fix its fold status
|
||
|
int lineCurrent = styler.GetLine(startPos);
|
||
|
if (startPos > 0) {
|
||
|
isFoldingAll = false;
|
||
|
if (lineCurrent > 0) {
|
||
|
lineCurrent--;
|
||
|
startPos = styler.LineStart(lineCurrent);
|
||
|
}
|
||
|
}
|
||
|
// vars for style of previous/current/next lines
|
||
|
int style = GetStyleFirstWord(lineCurrent,styler);
|
||
|
int stylePrev = 0;
|
||
|
|
||
|
// find the first previous line without continuation character at the end
|
||
|
while ((lineCurrent > 0 && IsContinuationLine(lineCurrent,styler)) ||
|
||
|
(lineCurrent > 1 && IsContinuationLine(lineCurrent-1,styler))) {
|
||
|
lineCurrent--;
|
||
|
startPos = styler.LineStart(lineCurrent);
|
||
|
}
|
||
|
if (lineCurrent > 0) {
|
||
|
stylePrev = GetStyleFirstWord(lineCurrent-1,styler);
|
||
|
}
|
||
|
// vars for getting first word to check for keywords
|
||
|
bool FirstWordStart = false;
|
||
|
bool FirstWordEnd = false;
|
||
|
|
||
|
const unsigned int KEYWORD_MAX = 10;
|
||
|
char szKeyword[KEYWORD_MAX]="";
|
||
|
unsigned int szKeywordlen = 0;
|
||
|
|
||
|
char szDo[3]="";
|
||
|
int szDolen = 0;
|
||
|
bool DoFoundLast = false;
|
||
|
|
||
|
// var for indentlevel
|
||
|
int levelCurrent = SC_FOLDLEVELBASE;
|
||
|
if (lineCurrent > 0) {
|
||
|
levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
|
||
|
}
|
||
|
int levelNext = levelCurrent;
|
||
|
|
||
|
int visibleChars = 0;
|
||
|
int functionCount = 0;
|
||
|
|
||
|
char chNext = styler.SafeGetCharAt(startPos);
|
||
|
char chPrev = '\0';
|
||
|
char chPrevPrev = '\0';
|
||
|
char chPrevPrevPrev = '\0';
|
||
|
|
||
|
for (int i = startPos; i < endPos; i++) {
|
||
|
|
||
|
char ch = chNext;
|
||
|
chNext = styler.SafeGetCharAt(i + 1);
|
||
|
|
||
|
if ((ch > 0) && setWord.Contains(ch)) {
|
||
|
visibleChars++;
|
||
|
}
|
||
|
|
||
|
// get the syle for the current character neede to check in comment
|
||
|
int stylech = styler.StyleAt(i);
|
||
|
|
||
|
// get first word for the line for indent check max 9 characters
|
||
|
if (FirstWordStart && (!(FirstWordEnd))) {
|
||
|
if ((ch > 0) && !setWord.Contains(ch)) {
|
||
|
FirstWordEnd = true;
|
||
|
}
|
||
|
else if (szKeywordlen < KEYWORD_MAX - 1) {
|
||
|
szKeyword[szKeywordlen++] = static_cast<char>(tolower(ch));
|
||
|
szKeyword[szKeywordlen] = '\0';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// start the capture of the first word
|
||
|
if (!(FirstWordStart)) {
|
||
|
if ((ch > 0) && (setWord.Contains(ch) || setWordStart.Contains(ch) || ch == ';' || ch == '/')) {
|
||
|
FirstWordStart = true;
|
||
|
if (szKeywordlen < KEYWORD_MAX - 1) {
|
||
|
szKeyword[szKeywordlen++] = static_cast<char>(tolower(ch));
|
||
|
szKeyword[szKeywordlen] = '\0';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// only process this logic when not in comment section
|
||
|
if (stylech != SCE_POWERPRO_COMMENTLINE) {
|
||
|
if (DoFoundLast) {
|
||
|
if (DoFoundLast && (ch > 0) && setWord.Contains(ch)) {
|
||
|
DoFoundLast = false;
|
||
|
}
|
||
|
}
|
||
|
// find out if the word "do" is the last on a "if" line
|
||
|
if (FirstWordEnd && strcmp(szKeyword,"if") == 0) {
|
||
|
if (szDolen == 2) {
|
||
|
szDo[0] = szDo[1];
|
||
|
szDo[1] = static_cast<char>(tolower(ch));
|
||
|
szDo[2] = '\0';
|
||
|
if (strcmp(szDo,"do") == 0 ) {
|
||
|
DoFoundLast = true;
|
||
|
}
|
||
|
}
|
||
|
else if (szDolen < 2) {
|
||
|
szDo[szDolen++] = static_cast<char>(tolower(ch));
|
||
|
szDo[szDolen] = '\0';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// End of Line found so process the information
|
||
|
if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) {
|
||
|
|
||
|
// **************************
|
||
|
// Folding logic for Keywords
|
||
|
// **************************
|
||
|
|
||
|
// if a keyword is found on the current line and the line doesn't end with ;;+ (continuation)
|
||
|
// and we are not inside a commentblock.
|
||
|
if (szKeywordlen > 0 &&
|
||
|
(!(chPrev == '+' && chPrevPrev == ';' && chPrevPrevPrev ==';')) &&
|
||
|
((!(IsStreamCommentStyle(style)) || foldInComment)) ) {
|
||
|
|
||
|
// only fold "if" last keyword is "then" (else its a one line if)
|
||
|
if (strcmp(szKeyword,"if") == 0 && DoFoundLast) {
|
||
|
levelNext++;
|
||
|
}
|
||
|
// create new fold for these words
|
||
|
if (strcmp(szKeyword,"for") == 0) {
|
||
|
levelNext++;
|
||
|
}
|
||
|
|
||
|
//handle folding for functions/labels
|
||
|
//Note: Functions and labels don't have an explicit end like [end function]
|
||
|
// 1. functions/labels end at the start of another function
|
||
|
// 2. functions/labels end at the end of the file
|
||
|
if ((strcmp(szKeyword,"function") == 0) || (szKeywordlen > 0 && szKeyword[0] == '@')) {
|
||
|
if (isFoldingAll) { //if we're folding the whole document (recursivly by lua script)
|
||
|
|
||
|
if (functionCount > 0) {
|
||
|
levelCurrent--;
|
||
|
} else {
|
||
|
levelNext++;
|
||
|
}
|
||
|
functionCount++;
|
||
|
|
||
|
} else { //if just folding a small piece (by clicking on the minus sign next to the word)
|
||
|
levelCurrent--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// end the fold for these words before the current line
|
||
|
if (strcmp(szKeyword,"endif") == 0 || strcmp(szKeyword,"endfor") == 0) {
|
||
|
levelNext--;
|
||
|
levelCurrent--;
|
||
|
}
|
||
|
// end the fold for these words before the current line and Start new fold
|
||
|
if (strcmp(szKeyword,"else") == 0 || strcmp(szKeyword,"elseif") == 0 ) {
|
||
|
levelCurrent--;
|
||
|
}
|
||
|
}
|
||
|
// Preprocessor and Comment folding
|
||
|
int styleNext = GetStyleFirstWord(lineCurrent + 1,styler);
|
||
|
|
||
|
// *********************************
|
||
|
// Folding logic for Comment blocks
|
||
|
// *********************************
|
||
|
if (foldComment && IsStreamCommentStyle(style)) {
|
||
|
// Start of a comment block
|
||
|
if (!(stylePrev==style) && IsStreamCommentStyle(styleNext) && styleNext==style) {
|
||
|
levelNext++;
|
||
|
}
|
||
|
// fold till the last line for normal comment lines
|
||
|
else if (IsStreamCommentStyle(stylePrev)
|
||
|
&& !(styleNext == SCE_POWERPRO_COMMENTLINE)
|
||
|
&& stylePrev == SCE_POWERPRO_COMMENTLINE
|
||
|
&& style == SCE_POWERPRO_COMMENTLINE) {
|
||
|
levelNext--;
|
||
|
}
|
||
|
// fold till the one but last line for Blockcomment lines
|
||
|
else if (IsStreamCommentStyle(stylePrev)
|
||
|
&& !(styleNext == SCE_POWERPRO_COMMENTBLOCK)
|
||
|
&& style == SCE_POWERPRO_COMMENTBLOCK) {
|
||
|
levelNext--;
|
||
|
levelCurrent--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int levelUse = levelCurrent;
|
||
|
int lev = levelUse | levelNext << 16;
|
||
|
if (visibleChars == 0 && foldCompact)
|
||
|
lev |= SC_FOLDLEVELWHITEFLAG;
|
||
|
if (levelUse < levelNext) {
|
||
|
lev |= SC_FOLDLEVELHEADERFLAG;
|
||
|
}
|
||
|
if (lev != styler.LevelAt(lineCurrent)) {
|
||
|
styler.SetLevel(lineCurrent, lev);
|
||
|
}
|
||
|
|
||
|
// reset values for the next line
|
||
|
lineCurrent++;
|
||
|
stylePrev = style;
|
||
|
style = styleNext;
|
||
|
levelCurrent = levelNext;
|
||
|
visibleChars = 0;
|
||
|
|
||
|
// if the last characters are ;;+ then don't reset since the line continues on the next line.
|
||
|
if (chPrev == '+' && chPrevPrev == ';' && chPrevPrevPrev == ';') {
|
||
|
//do nothing
|
||
|
} else {
|
||
|
szKeywordlen = 0;
|
||
|
szDolen = 0;
|
||
|
FirstWordStart = false;
|
||
|
FirstWordEnd = false;
|
||
|
DoFoundLast = false;
|
||
|
//blank out keyword
|
||
|
for (unsigned int i = 0; i < KEYWORD_MAX; i++) {
|
||
|
szKeyword[i] = '\0';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// save the last processed characters
|
||
|
if ((ch > 0) && !isspacechar(ch)) {
|
||
|
chPrevPrevPrev = chPrevPrev;
|
||
|
chPrevPrev = chPrev;
|
||
|
chPrev = ch;
|
||
|
visibleChars++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//close folds on the last line - without this a 'phantom'
|
||
|
//fold can appear when an open fold is on the last line
|
||
|
//this can occur because functions and labels don't have an explicit end
|
||
|
if (lineCurrent >= lastLine) {
|
||
|
int lev = 0;
|
||
|
lev |= SC_FOLDLEVELWHITEFLAG;
|
||
|
styler.SetLevel(lineCurrent, lev);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
static const char * const powerProWordLists[] = {
|
||
|
"Keyword list 1",
|
||
|
"Keyword list 2",
|
||
|
"Keyword list 3",
|
||
|
"Keyword list 4",
|
||
|
0,
|
||
|
};
|
||
|
|
||
|
static void ColourisePowerProDocWrapper(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
|
||
|
Accessor &styler) {
|
||
|
ColourisePowerProDoc(startPos, length, initStyle, keywordlists, styler, false);
|
||
|
}
|
||
|
|
||
|
LexerModule lmPowerPro(SCLEX_POWERPRO, ColourisePowerProDocWrapper, "powerpro", FoldPowerProDoc, powerProWordLists);
|