You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
8.9 KiB
309 lines
8.9 KiB
// Scintilla source code edit control |
|
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org> |
|
/* |
|
This is the Lexer for Gui4Cli, included in SciLexer.dll |
|
- by d. Keletsekis, 2/10/2003 |
|
|
|
To add to SciLexer.dll: |
|
1. Add the values below to INCLUDE\Scintilla.iface |
|
2. Run the include/HFacer.py script |
|
3. Run the src/lexGen.py script |
|
|
|
val SCE_GC_DEFAULT=0 |
|
val SCE_GC_COMMENTLINE=1 |
|
val SCE_GC_COMMENTBLOCK=2 |
|
val SCE_GC_GLOBAL=3 |
|
val SCE_GC_EVENT=4 |
|
val SCE_GC_ATTRIBUTE=5 |
|
val SCE_GC_CONTROL=6 |
|
val SCE_GC_COMMAND=7 |
|
val SCE_GC_STRING=8 |
|
val SCE_GC_OPERATOR=9 |
|
*/ |
|
|
|
#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" |
|
|
|
#define debug Platform::DebugPrintf |
|
|
|
static inline bool IsAWordChar(const int ch) { |
|
return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch =='\\'); |
|
} |
|
|
|
static inline bool IsAWordStart(const int ch) { |
|
return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.'); |
|
} |
|
|
|
inline bool isGCOperator(int ch) |
|
{ if (isalnum(ch)) |
|
return false; |
|
// '.' left out as it is used to make up numbers |
|
if (ch == '*' || ch == '/' || ch == '-' || ch == '+' || |
|
ch == '(' || ch == ')' || ch == '=' || ch == '%' || |
|
ch == '[' || ch == ']' || ch == '<' || ch == '>' || |
|
ch == ',' || ch == ';' || ch == ':') |
|
return true; |
|
return false; |
|
} |
|
|
|
#define isSpace(x) ((x)==' ' || (x)=='\t') |
|
#define isNL(x) ((x)=='\n' || (x)=='\r') |
|
#define isSpaceOrNL(x) (isSpace(x) || isNL(x)) |
|
#define BUFFSIZE 500 |
|
#define isFoldPoint(x) ((styler.LevelAt(x) & SC_FOLDLEVELNUMBERMASK) == 1024) |
|
|
|
static void colorFirstWord(WordList *keywordlists[], Accessor &styler, |
|
StyleContext *sc, char *buff, int length, int) |
|
{ |
|
int c = 0; |
|
while (sc->More() && isSpaceOrNL(sc->ch)) |
|
{ sc->Forward(); |
|
} |
|
styler.ColourTo(sc->currentPos - 1, sc->state); |
|
|
|
if (!IsAWordChar(sc->ch)) // comment, marker, etc.. |
|
return; |
|
|
|
while (sc->More() && !isSpaceOrNL(sc->ch) && (c < length-1) && !isGCOperator(sc->ch)) |
|
{ buff[c] = static_cast<char>(sc->ch); |
|
++c; sc->Forward(); |
|
} |
|
buff[c] = '\0'; |
|
char *p = buff; |
|
while (*p) // capitalize.. |
|
{ if (islower(*p)) *p = static_cast<char>(toupper(*p)); |
|
++p; |
|
} |
|
|
|
WordList &kGlobal = *keywordlists[0]; // keyword lists set by the user |
|
WordList &kEvent = *keywordlists[1]; |
|
WordList &kAttribute = *keywordlists[2]; |
|
WordList &kControl = *keywordlists[3]; |
|
WordList &kCommand = *keywordlists[4]; |
|
|
|
int state = 0; |
|
// int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK; |
|
// debug ("line = %d, level = %d", line, level); |
|
|
|
if (kGlobal.InList(buff)) state = SCE_GC_GLOBAL; |
|
else if (kAttribute.InList(buff)) state = SCE_GC_ATTRIBUTE; |
|
else if (kControl.InList(buff)) state = SCE_GC_CONTROL; |
|
else if (kCommand.InList(buff)) state = SCE_GC_COMMAND; |
|
else if (kEvent.InList(buff)) state = SCE_GC_EVENT; |
|
|
|
if (state) |
|
{ sc->ChangeState(state); |
|
styler.ColourTo(sc->currentPos - 1, sc->state); |
|
sc->ChangeState(SCE_GC_DEFAULT); |
|
} |
|
else |
|
{ sc->ChangeState(SCE_GC_DEFAULT); |
|
styler.ColourTo(sc->currentPos - 1, sc->state); |
|
} |
|
} |
|
|
|
// Main colorizing function called by Scintilla |
|
static void |
|
ColouriseGui4CliDoc(unsigned int startPos, int length, int initStyle, |
|
WordList *keywordlists[], Accessor &styler) |
|
{ |
|
styler.StartAt(startPos); |
|
|
|
int quotestart = 0, oldstate, currentline = styler.GetLine(startPos); |
|
styler.StartSegment(startPos); |
|
bool noforward; |
|
char buff[BUFFSIZE+1]; // buffer for command name |
|
|
|
StyleContext sc(startPos, length, initStyle, styler); |
|
buff[0] = '\0'; // cbuff = 0; |
|
|
|
if (sc.state != SCE_GC_COMMENTBLOCK) // colorize 1st word.. |
|
colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline); |
|
|
|
while (sc.More()) |
|
{ noforward = 0; |
|
|
|
switch (sc.ch) |
|
{ |
|
case '/': |
|
if (sc.state == SCE_GC_COMMENTBLOCK || sc.state == SCE_GC_STRING) |
|
break; |
|
if (sc.chNext == '/') // line comment |
|
{ sc.SetState (SCE_GC_COMMENTLINE); |
|
sc.Forward(); |
|
styler.ColourTo(sc.currentPos, sc.state); |
|
} |
|
else if (sc.chNext == '*') // block comment |
|
{ sc.SetState(SCE_GC_COMMENTBLOCK); |
|
sc.Forward(); |
|
styler.ColourTo(sc.currentPos, sc.state); |
|
} |
|
else |
|
styler.ColourTo(sc.currentPos, sc.state); |
|
break; |
|
|
|
case '*': // end of comment block, or operator.. |
|
if (sc.state == SCE_GC_STRING) |
|
break; |
|
if (sc.state == SCE_GC_COMMENTBLOCK && sc.chNext == '/') |
|
{ sc.Forward(); |
|
styler.ColourTo(sc.currentPos, sc.state); |
|
sc.ChangeState (SCE_GC_DEFAULT); |
|
} |
|
else |
|
styler.ColourTo(sc.currentPos, sc.state); |
|
break; |
|
|
|
case '\'': case '\"': // strings.. |
|
if (sc.state == SCE_GC_COMMENTBLOCK || sc.state == SCE_GC_COMMENTLINE) |
|
break; |
|
if (sc.state == SCE_GC_STRING) |
|
{ if (sc.ch == quotestart) // match same quote char.. |
|
{ styler.ColourTo(sc.currentPos, sc.state); |
|
sc.ChangeState(SCE_GC_DEFAULT); |
|
quotestart = 0; |
|
} } |
|
else |
|
{ styler.ColourTo(sc.currentPos - 1, sc.state); |
|
sc.ChangeState(SCE_GC_STRING); |
|
quotestart = sc.ch; |
|
} |
|
break; |
|
|
|
case ';': // end of commandline character |
|
if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE && |
|
sc.state != SCE_GC_STRING) |
|
{ |
|
styler.ColourTo(sc.currentPos - 1, sc.state); |
|
styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR); |
|
sc.ChangeState(SCE_GC_DEFAULT); |
|
sc.Forward(); |
|
colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline); |
|
noforward = 1; // don't move forward - already positioned at next char.. |
|
} |
|
break; |
|
|
|
case '+': case '-': case '=': case '!': // operators.. |
|
case '<': case '>': case '&': case '|': case '$': |
|
if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE && |
|
sc.state != SCE_GC_STRING) |
|
{ |
|
styler.ColourTo(sc.currentPos - 1, sc.state); |
|
styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR); |
|
sc.ChangeState(SCE_GC_DEFAULT); |
|
} |
|
break; |
|
|
|
case '\\': // escape - same as operator, but also mark in strings.. |
|
if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE) |
|
{ |
|
oldstate = sc.state; |
|
styler.ColourTo(sc.currentPos - 1, sc.state); |
|
sc.Forward(); // mark also the next char.. |
|
styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR); |
|
sc.ChangeState(oldstate); |
|
} |
|
break; |
|
|
|
case '\n': case '\r': |
|
++currentline; |
|
if (sc.state == SCE_GC_COMMENTLINE) |
|
{ styler.ColourTo(sc.currentPos, sc.state); |
|
sc.ChangeState (SCE_GC_DEFAULT); |
|
} |
|
else if (sc.state != SCE_GC_COMMENTBLOCK) |
|
{ colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline); |
|
noforward = 1; // don't move forward - already positioned at next char.. |
|
} |
|
break; |
|
|
|
// case ' ': case '\t': |
|
// default : |
|
} |
|
|
|
if (!noforward) sc.Forward(); |
|
|
|
} |
|
sc.Complete(); |
|
} |
|
|
|
// Main folding function called by Scintilla - (based on props (.ini) files function) |
|
static void FoldGui4Cli(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; |
|
|
|
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_GC_EVENT || style == SCE_GC_GLOBAL) |
|
{ headerPoint = true; // fold at events and globals |
|
} |
|
|
|
if (atEOL) |
|
{ int lev = SC_FOLDLEVELBASE+1; |
|
|
|
if (headerPoint) |
|
lev = SC_FOLDLEVELBASE; |
|
|
|
if (visibleChars == 0 && foldCompact) |
|
lev |= SC_FOLDLEVELWHITEFLAG; |
|
|
|
if (headerPoint) |
|
lev |= SC_FOLDLEVELHEADERFLAG; |
|
|
|
if (lev != styler.LevelAt(lineCurrent)) // set level, if not already correct |
|
{ styler.SetLevel(lineCurrent, lev); |
|
} |
|
|
|
lineCurrent++; // re-initialize our flags |
|
visibleChars = 0; |
|
headerPoint = false; |
|
} |
|
|
|
if (!(isspacechar(ch))) // || (style == SCE_GC_COMMENTLINE) || (style != SCE_GC_COMMENTBLOCK))) |
|
visibleChars++; |
|
} |
|
|
|
int lev = headerPoint ? SC_FOLDLEVELBASE : SC_FOLDLEVELBASE+1; |
|
int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; |
|
styler.SetLevel(lineCurrent, lev | flagsNext); |
|
} |
|
|
|
// I have no idea what these are for.. probably accessible by some message. |
|
static const char * const gui4cliWordListDesc[] = { |
|
"Globals", "Events", "Attributes", "Control", "Commands", |
|
0 |
|
}; |
|
|
|
// Declare language & pass our function pointers to Scintilla |
|
LexerModule lmGui4Cli(SCLEX_GUI4CLI, ColouriseGui4CliDoc, "gui4cli", FoldGui4Cli, gui4cliWordListDesc); |
|
|
|
#undef debug |
|
|
|
|