2009-04-24 23:35:41 +00:00
|
|
|
// 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
|
2015-06-07 21:19:26 +00:00
|
|
|
2. Run the scripts/HFacer.py script
|
|
|
|
3. Run the scripts/LexGen.py script
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
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 <stdio.h>
|
|
|
|
#include <stdarg.h>
|
2010-08-21 23:59:56 +00:00
|
|
|
#include <assert.h>
|
|
|
|
#include <ctype.h>
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2010-08-21 23:59:56 +00:00
|
|
|
#include "ILexer.h"
|
|
|
|
#include "Scintilla.h"
|
|
|
|
#include "SciLexer.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2010-08-21 23:59:56 +00:00
|
|
|
#include "WordList.h"
|
|
|
|
#include "LexAccessor.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
#include "Accessor.h"
|
|
|
|
#include "StyleContext.h"
|
2010-08-21 23:59:56 +00:00
|
|
|
#include "CharacterSet.h"
|
|
|
|
#include "LexerModule.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
using namespace Scintilla;
|
|
|
|
|
|
|
|
#define debug Platform::DebugPrintf
|
|
|
|
|
|
|
|
static inline bool IsAWordChar(const int ch) {
|
|
|
|
return (ch < 0x80) && (isalnum(ch) || 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,
|
2019-05-04 18:14:48 +00:00
|
|
|
StyleContext *sc, char *buff, Sci_Position length, Sci_Position)
|
2009-04-24 23:35:41 +00:00
|
|
|
{
|
2019-05-04 18:14:48 +00:00
|
|
|
Sci_Position c = 0;
|
2009-04-24 23:35:41 +00:00
|
|
|
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
|
2019-05-04 18:14:48 +00:00
|
|
|
ColouriseGui4CliDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
|
2009-04-24 23:35:41 +00:00
|
|
|
WordList *keywordlists[], Accessor &styler)
|
|
|
|
{
|
|
|
|
styler.StartAt(startPos);
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
Sci_Position currentline = styler.GetLine(startPos);
|
|
|
|
int quotestart = 0, oldstate;
|
2009-04-24 23:35:41 +00:00
|
|
|
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)
|
2019-05-04 18:14:48 +00:00
|
|
|
static void FoldGui4Cli(Sci_PositionU startPos, Sci_Position length, int,
|
2009-04-24 23:35:41 +00:00
|
|
|
WordList *[], Accessor &styler)
|
|
|
|
{
|
|
|
|
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
Sci_PositionU endPos = startPos + length;
|
2009-04-24 23:35:41 +00:00
|
|
|
int visibleChars = 0;
|
2019-05-04 18:14:48 +00:00
|
|
|
Sci_Position lineCurrent = styler.GetLine(startPos);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
char chNext = styler[startPos];
|
|
|
|
int styleNext = styler.StyleAt(startPos);
|
|
|
|
bool headerPoint = false;
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
for (Sci_PositionU i = startPos; i < endPos; i++)
|
2009-04-24 23:35:41 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
|