295 lines
8.2 KiB
C++
295 lines
8.2 KiB
C++
|
// Scintilla source code edit control
|
||
|
/** @file LexInno.cxx
|
||
|
** Lexer for Inno Setup scripts.
|
||
|
**/
|
||
|
// Written by Friedrich Vedder <fvedd@t-online.de>, using code from LexOthers.cxx.
|
||
|
// The License.txt file describes the conditions under which this software may be distributed.
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdarg.h>
|
||
|
|
||
|
#include "Platform.h"
|
||
|
|
||
|
#include "PropSet.h"
|
||
|
#include "Accessor.h"
|
||
|
#include "StyleContext.h"
|
||
|
#include "KeyWords.h"
|
||
|
#include "Scintilla.h"
|
||
|
#include "SciLexer.h"
|
||
|
|
||
|
#ifdef SCI_NAMESPACE
|
||
|
using namespace Scintilla;
|
||
|
#endif
|
||
|
|
||
|
static void ColouriseInnoDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler) {
|
||
|
int state = SCE_INNO_DEFAULT;
|
||
|
char chPrev;
|
||
|
char ch = 0;
|
||
|
char chNext = styler[startPos];
|
||
|
int lengthDoc = startPos + length;
|
||
|
char *buffer = new char[length];
|
||
|
int bufferCount = 0;
|
||
|
bool isBOL, isEOL, isWS, isBOLWS = 0;
|
||
|
|
||
|
WordList §ionKeywords = *keywordLists[0];
|
||
|
WordList &standardKeywords = *keywordLists[1];
|
||
|
WordList ¶meterKeywords = *keywordLists[2];
|
||
|
WordList &preprocessorKeywords = *keywordLists[3];
|
||
|
WordList &pascalKeywords = *keywordLists[4];
|
||
|
WordList &userKeywords = *keywordLists[5];
|
||
|
|
||
|
// Go through all provided text segment
|
||
|
// using the hand-written state machine shown below
|
||
|
styler.StartAt(startPos);
|
||
|
styler.StartSegment(startPos);
|
||
|
for (int i = startPos; i < lengthDoc; i++) {
|
||
|
chPrev = ch;
|
||
|
ch = chNext;
|
||
|
chNext = styler.SafeGetCharAt(i + 1);
|
||
|
|
||
|
if (styler.IsLeadByte(ch)) {
|
||
|
chNext = styler.SafeGetCharAt(i + 2);
|
||
|
i++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
isBOL = (chPrev == 0) || (chPrev == '\n') || (chPrev == '\r' && ch != '\n');
|
||
|
isBOLWS = (isBOL) ? 1 : (isBOLWS && (chPrev == ' ' || chPrev == '\t'));
|
||
|
isEOL = (ch == '\n' || ch == '\r');
|
||
|
isWS = (ch == ' ' || ch == '\t');
|
||
|
|
||
|
switch(state) {
|
||
|
case SCE_INNO_DEFAULT:
|
||
|
if (ch == ';' && isBOLWS) {
|
||
|
// Start of a comment
|
||
|
state = SCE_INNO_COMMENT;
|
||
|
} else if (ch == '[' && isBOLWS) {
|
||
|
// Start of a section name
|
||
|
bufferCount = 0;
|
||
|
state = SCE_INNO_SECTION;
|
||
|
} else if (ch == '#' && isBOLWS) {
|
||
|
// Start of a preprocessor directive
|
||
|
state = SCE_INNO_PREPROC;
|
||
|
} else if (ch == '{' && chNext == '#') {
|
||
|
// Start of a preprocessor inline directive
|
||
|
state = SCE_INNO_PREPROC_INLINE;
|
||
|
} else if ((ch == '{' && (chNext == ' ' || chNext == '\t'))
|
||
|
|| (ch == '(' && chNext == '*')) {
|
||
|
// Start of a Pascal comment
|
||
|
state = SCE_INNO_COMMENT_PASCAL;
|
||
|
} else if (ch == '"') {
|
||
|
// Start of a double-quote string
|
||
|
state = SCE_INNO_STRING_DOUBLE;
|
||
|
} else if (ch == '\'') {
|
||
|
// Start of a single-quote string
|
||
|
state = SCE_INNO_STRING_SINGLE;
|
||
|
} else if (isascii(ch) && (isalpha(ch) || (ch == '_'))) {
|
||
|
// Start of an identifier
|
||
|
bufferCount = 0;
|
||
|
buffer[bufferCount++] = static_cast<char>(tolower(ch));
|
||
|
state = SCE_INNO_IDENTIFIER;
|
||
|
} else {
|
||
|
// Style it the default style
|
||
|
styler.ColourTo(i,SCE_INNO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_INNO_COMMENT:
|
||
|
if (isEOL) {
|
||
|
state = SCE_INNO_DEFAULT;
|
||
|
styler.ColourTo(i,SCE_INNO_COMMENT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_INNO_IDENTIFIER:
|
||
|
if (isascii(ch) && (isalnum(ch) || (ch == '_'))) {
|
||
|
buffer[bufferCount++] = static_cast<char>(tolower(ch));
|
||
|
} else {
|
||
|
state = SCE_INNO_DEFAULT;
|
||
|
buffer[bufferCount] = '\0';
|
||
|
|
||
|
// Check if the buffer contains a keyword
|
||
|
if (standardKeywords.InList(buffer)) {
|
||
|
styler.ColourTo(i-1,SCE_INNO_KEYWORD);
|
||
|
} else if (parameterKeywords.InList(buffer)) {
|
||
|
styler.ColourTo(i-1,SCE_INNO_PARAMETER);
|
||
|
} else if (pascalKeywords.InList(buffer)) {
|
||
|
styler.ColourTo(i-1,SCE_INNO_KEYWORD_PASCAL);
|
||
|
} else if (userKeywords.InList(buffer)) {
|
||
|
styler.ColourTo(i-1,SCE_INNO_KEYWORD_USER);
|
||
|
} else {
|
||
|
styler.ColourTo(i-1,SCE_INNO_DEFAULT);
|
||
|
}
|
||
|
|
||
|
// Push back the faulty character
|
||
|
chNext = styler[i--];
|
||
|
ch = chPrev;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_INNO_SECTION:
|
||
|
if (ch == ']') {
|
||
|
state = SCE_INNO_DEFAULT;
|
||
|
buffer[bufferCount] = '\0';
|
||
|
|
||
|
// Check if the buffer contains a section name
|
||
|
if (sectionKeywords.InList(buffer)) {
|
||
|
styler.ColourTo(i,SCE_INNO_SECTION);
|
||
|
} else {
|
||
|
styler.ColourTo(i,SCE_INNO_DEFAULT);
|
||
|
}
|
||
|
} else if (isascii(ch) && (isalnum(ch) || (ch == '_'))) {
|
||
|
buffer[bufferCount++] = static_cast<char>(tolower(ch));
|
||
|
} else {
|
||
|
state = SCE_INNO_DEFAULT;
|
||
|
styler.ColourTo(i,SCE_INNO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_INNO_PREPROC:
|
||
|
if (isWS || isEOL) {
|
||
|
if (isascii(chPrev) && isalpha(chPrev)) {
|
||
|
state = SCE_INNO_DEFAULT;
|
||
|
buffer[bufferCount] = '\0';
|
||
|
|
||
|
// Check if the buffer contains a preprocessor directive
|
||
|
if (preprocessorKeywords.InList(buffer)) {
|
||
|
styler.ColourTo(i-1,SCE_INNO_PREPROC);
|
||
|
} else {
|
||
|
styler.ColourTo(i-1,SCE_INNO_DEFAULT);
|
||
|
}
|
||
|
|
||
|
// Push back the faulty character
|
||
|
chNext = styler[i--];
|
||
|
ch = chPrev;
|
||
|
}
|
||
|
} else if (isascii(ch) && isalpha(ch)) {
|
||
|
if (chPrev == '#' || chPrev == ' ' || chPrev == '\t')
|
||
|
bufferCount = 0;
|
||
|
buffer[bufferCount++] = static_cast<char>(tolower(ch));
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_INNO_STRING_DOUBLE:
|
||
|
if (ch == '"' || isEOL) {
|
||
|
state = SCE_INNO_DEFAULT;
|
||
|
styler.ColourTo(i,SCE_INNO_STRING_DOUBLE);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_INNO_STRING_SINGLE:
|
||
|
if (ch == '\'' || isEOL) {
|
||
|
state = SCE_INNO_DEFAULT;
|
||
|
styler.ColourTo(i,SCE_INNO_STRING_SINGLE);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_INNO_PREPROC_INLINE:
|
||
|
if (ch == '}') {
|
||
|
state = SCE_INNO_DEFAULT;
|
||
|
styler.ColourTo(i,SCE_INNO_PREPROC_INLINE);
|
||
|
} else if (isEOL) {
|
||
|
state = SCE_INNO_DEFAULT;
|
||
|
styler.ColourTo(i,SCE_INNO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SCE_INNO_COMMENT_PASCAL:
|
||
|
if (ch == '}' || (ch == ')' && chPrev == '*')) {
|
||
|
state = SCE_INNO_DEFAULT;
|
||
|
styler.ColourTo(i,SCE_INNO_COMMENT_PASCAL);
|
||
|
} else if (isEOL) {
|
||
|
state = SCE_INNO_DEFAULT;
|
||
|
styler.ColourTo(i,SCE_INNO_DEFAULT);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
delete []buffer;
|
||
|
}
|
||
|
|
||
|
static const char * const innoWordListDesc[] = {
|
||
|
"Sections",
|
||
|
"Keywords",
|
||
|
"Parameters",
|
||
|
"Preprocessor directives",
|
||
|
"Pascal keywords",
|
||
|
"User defined keywords",
|
||
|
0
|
||
|
};
|
||
|
|
||
|
static void FoldInnoDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
|
||
|
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
|
||
|
|
||
|
unsigned int endPos = startPos + length;
|
||
|
int visibleChars = 0;
|
||
|
int lineCurrent = styler.GetLine(startPos);
|
||
|
|
||
|
char chNext = styler[startPos];
|
||
|
int styleNext = styler.StyleAt(startPos);
|
||
|
bool headerPoint = false;
|
||
|
int lev;
|
||
|
|
||
|
for (unsigned int i = startPos; i < endPos; i++) {
|
||
|
char ch = chNext;
|
||
|
chNext = styler[i+1];
|
||
|
|
||
|
int style = styleNext;
|
||
|
styleNext = styler.StyleAt(i + 1);
|
||
|
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
|
||
|
|
||
|
if (style == SCE_INNO_SECTION)
|
||
|
headerPoint = true;
|
||
|
|
||
|
if (atEOL) {
|
||
|
lev = SC_FOLDLEVELBASE;
|
||
|
|
||
|
if (lineCurrent > 0) {
|
||
|
int levelPrevious = styler.LevelAt(lineCurrent - 1);
|
||
|
|
||
|
if (levelPrevious & SC_FOLDLEVELHEADERFLAG)
|
||
|
lev = SC_FOLDLEVELBASE + 1;
|
||
|
else
|
||
|
lev = levelPrevious & SC_FOLDLEVELNUMBERMASK;
|
||
|
}
|
||
|
|
||
|
if (headerPoint)
|
||
|
lev = SC_FOLDLEVELBASE;
|
||
|
|
||
|
if (visibleChars == 0 && foldCompact)
|
||
|
lev |= SC_FOLDLEVELWHITEFLAG;
|
||
|
|
||
|
if (headerPoint)
|
||
|
lev |= SC_FOLDLEVELHEADERFLAG;
|
||
|
|
||
|
if (lev != styler.LevelAt(lineCurrent))
|
||
|
styler.SetLevel(lineCurrent, lev);
|
||
|
|
||
|
lineCurrent++;
|
||
|
visibleChars = 0;
|
||
|
headerPoint = false;
|
||
|
}
|
||
|
if (!isspacechar(ch))
|
||
|
visibleChars++;
|
||
|
}
|
||
|
|
||
|
if (lineCurrent > 0) {
|
||
|
int levelPrevious = styler.LevelAt(lineCurrent - 1);
|
||
|
|
||
|
if (levelPrevious & SC_FOLDLEVELHEADERFLAG)
|
||
|
lev = SC_FOLDLEVELBASE + 1;
|
||
|
else
|
||
|
lev = levelPrevious & SC_FOLDLEVELNUMBERMASK;
|
||
|
} else {
|
||
|
lev = SC_FOLDLEVELBASE;
|
||
|
}
|
||
|
int flagsNext = styler.LevelAt(lineCurrent);
|
||
|
styler.SetLevel(lineCurrent, lev | flagsNext & ~SC_FOLDLEVELNUMBERMASK);
|
||
|
}
|
||
|
|
||
|
LexerModule lmInno(SCLEX_INNOSETUP, ColouriseInnoDoc, "inno", FoldInnoDoc, innoWordListDesc);
|