Neil Hodgson wrote:
   In LexCPP, the IsStateWord function is unused.

So are IsStateComment and IsStateString, presents in the latest version of LexCPP. I don't know what are these functions, they can be old vestigal code...

In a list of
#include lines, every second line is wrongly styled.

Uh? They look fine for me... Either in <foo> or "bar" style.
Oh, if I put styling.within.preprocessor=0, I can see this...
I always have styling.within.preprocessor=1, that's why this flag was created...

OK, I believe I found what was wrong... I tested sc.atLineEnd, but unlike the similar tests in this lexer, I forgot to reset visibleChars to 0. I also added the PREPROCESSOR state to the list of initStyle that must not leak...

This is on
Windows with CR+LF line ends.
http://scintilla.sourceforge.net/AlternatingIncludes.png
The LexLua changes look OK.

Actually, it has a similar problem (initStyle), but preprocessors are a bit out of fashion in Lua...

   In the properties files, it is hard to untangle the generically
useful parts, such as better descriptions of lexical states, from
personal preferences.

Yes, sorry, it was mostly provided for the list of keywords.
And, indeed, for the more detailled comments.

Speaking of personal preference, I think you should remove the
# tpl is X and Mail specific
comment in html.properties, "X and Mail" was my previous employer...
tpl is probably still a valid (read "quite common") extension for html.

The ECMAScript standard does not list true and
false as keywords but as literals.
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf

I wasn't sure what you meant by literals...
Well, Netscape (inventor of JS) agrees: http://wp.netscape.com/eng/mozilla/3.0/handbook/javascript/ident.htm
I suppose null is also a literal, although Netscape writes:
"null, a special keyword denoting a null value"...
I removed true and false from my list of keywords, although I still find funny to see them like the other identifiers...
I put them in keywords2:
keywords2.*.js=true false null
but alas, it won't work in HTML or XML (SVG...).

--
Philippe Lhoste
--  (near) Paris -- France
--  http://Phi.Lho.free.fr
--  --  --  --  --  --  --  --  --  --  --  --  --  --
// Scintilla source code edit control
/** @file LexCPP.cxx
 ** Lexer for C++, C, Java, and JavaScript.
 **/
// Copyright 1998-2005 by Neil Hodgson <[EMAIL PROTECTED]>
// 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"

#define KEYWORD_BOXHEADER 1
#define KEYWORD_FOLDCONTRACTED 2

static bool IsOKBeforeRE(int ch) {
        return (ch == '(') || (ch == '=') || (ch == ',');
}

static inline bool IsAWordChar(int ch) {
        return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

static inline bool IsAWordStart(int ch) {
        return (ch < 0x80) && (isalpha(ch) || ch == '_');
}

static inline bool IsADoxygenChar(int ch) {
        return (islower(ch) || ch == '$' || ch == '@' ||
                ch == '\\' || ch == '&' || ch == '<' ||
                ch == '>' || ch == '#' || ch == '{' ||
                ch == '}' || ch == '[' || ch == ']');
}

static void ColouriseCppDoc(
        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];

        bool stylingWithinPreprocessor = 
styler.GetPropertyInt("styling.within.preprocessor") != 0;

        int chPrevNonWhite = ' ';
        int visibleChars = 0;
        bool lastWordWasUUID = false;

        // Do not leak onto next line
        if (initStyle == SCE_C_STRINGEOL ||
                initStyle == SCE_C_COMMENTLINE ||
                initStyle == SCE_C_COMMENTLINEDOC ||
                initStyle == SCE_C_PREPROCESSOR) {
                        initStyle = SCE_C_DEFAULT;
        }

        StyleContext sc(startPos, length, initStyle, styler);

        for (; sc.More(); sc.Forward()) {

                if (sc.atLineStart && (sc.state == SCE_C_STRING)) {
                        // Prevent SCE_C_STRINGEOL from leaking back to 
previous line
                        sc.SetState(SCE_C_STRING);
                }

                // Handle line continuation generically.
                if (sc.ch == '\\') {
                        if (sc.chNext == '\n' || sc.chNext == '\r') {
                                sc.Forward();
                                if (sc.ch == '\r' && sc.chNext == '\n') {
                                        sc.Forward();
                                }
                                continue;
                        }
                }

                // Determine if the current state should terminate.
                if (sc.state == SCE_C_OPERATOR) {
                        sc.SetState(SCE_C_DEFAULT);
                } else if (sc.state == SCE_C_NUMBER) {
                        // We accept almost anything because of hex. and number 
suffixes
                        if (!IsAWordChar(sc.ch)) {
                                sc.SetState(SCE_C_DEFAULT);
                        }
                } else if (sc.state == SCE_C_IDENTIFIER) {
                        if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
                                char s[100];
                                if (caseSensitive) {
                                        sc.GetCurrent(s, sizeof(s));
                                } else {
                                        sc.GetCurrentLowered(s, sizeof(s));
                                }
                                if (keywords.InList(s)) {
                                        lastWordWasUUID = strcmp(s, "uuid") == 
0;
                                        sc.ChangeState(SCE_C_WORD);
                                } else if (keywords2.InList(s)) {
                                        sc.ChangeState(SCE_C_WORD2);
                                } else if (keywords4.InList(s)) {
                                        sc.ChangeState(SCE_C_GLOBALCLASS);
                                }
                                sc.SetState(SCE_C_DEFAULT);
                        }
                } else if (sc.state == SCE_C_PREPROCESSOR) {
                        if (stylingWithinPreprocessor) {
                                if (IsASpace(sc.ch)) {
                                        sc.SetState(SCE_C_DEFAULT);
                                }
                        } else {
                                if ((sc.atLineEnd)) {
                                        sc.ForwardSetState(SCE_C_DEFAULT);
                                } else if (sc.Match('/', '*') || sc.Match('/', 
'/')) {
                                        sc.SetState(SCE_C_DEFAULT);
                                }
                        }
                } else if (sc.state == SCE_C_COMMENT) {
                        if (sc.Match('*', '/')) {
                                sc.Forward();
                                sc.ForwardSetState(SCE_C_DEFAULT);
                        }
                } else if (sc.state == SCE_C_COMMENTDOC) {
                        if (sc.Match('*', '/')) {
                                sc.Forward();
                                sc.ForwardSetState(SCE_C_DEFAULT);
                        } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc 
and Doxygen support
                                // Verify that we have the conditions to mark a 
comment-doc-keyword
                                if ((IsASpace(sc.chPrev) || sc.chPrev == '*') 
&& (!IsASpace(sc.chNext))) {
                                        sc.SetState(SCE_C_COMMENTDOCKEYWORD);
                                }
                        }
                } else if (sc.state == SCE_C_COMMENTLINE || sc.state == 
SCE_C_COMMENTLINEDOC) {
                        if (sc.atLineEnd) {
                                sc.ForwardSetState(SCE_C_DEFAULT);
                        }
                } else if (sc.state == SCE_C_COMMENTDOCKEYWORD) {
                        if (sc.Match('*', '/')) {
                                sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
                                sc.Forward();
                                sc.ForwardSetState(SCE_C_DEFAULT);
                        } else if (!IsADoxygenChar(sc.ch)) {
                                char s[100];
                                if (caseSensitive) {
                                        sc.GetCurrent(s, sizeof(s));
                                } else {
                                        sc.GetCurrentLowered(s, sizeof(s));
                                }
                                if (!isspace(sc.ch) || !keywords3.InList(s + 
1)) {
                                        
sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
                                }
                                sc.SetState(SCE_C_COMMENTDOC);
                        }
                } else if (sc.state == SCE_C_STRING) {
                        if (sc.ch == '\\') {
                                if (sc.chNext == '\"' || sc.chNext == '\'' || 
sc.chNext == '\\') {
                                        sc.Forward();
                                }
                        } else if (sc.ch == '\"') {
                                sc.ForwardSetState(SCE_C_DEFAULT);
                        } else if (sc.atLineEnd) {
                                sc.ChangeState(SCE_C_STRINGEOL);
                                sc.ForwardSetState(SCE_C_DEFAULT);
                        }
                } else if (sc.state == SCE_C_CHARACTER) {
                        if (sc.atLineEnd) {
                                sc.ChangeState(SCE_C_STRINGEOL);
                                sc.ForwardSetState(SCE_C_DEFAULT);
                        } else if (sc.ch == '\\') {
                                if (sc.chNext == '\"' || sc.chNext == '\'' || 
sc.chNext == '\\') {
                                        sc.Forward();
                                }
                        } else if (sc.ch == '\'') {
                                sc.ForwardSetState(SCE_C_DEFAULT);
                        }
                } else if (sc.state == SCE_C_REGEX) {
                        if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == '/') {
                                sc.ForwardSetState(SCE_C_DEFAULT);
                        } else if (sc.ch == '\\') {
                                // Gobble up the quoted character
                                if (sc.chNext == '\\' || sc.chNext == '/') {
                                        sc.Forward();
                                }
                        }
                } else if (sc.state == SCE_C_VERBATIM) {
                        if (sc.ch == '\"') {
                                if (sc.chNext == '\"') {
                                        sc.Forward();
                                } else {
                                        sc.ForwardSetState(SCE_C_DEFAULT);
                                }
                        }
                } else if (sc.state == SCE_C_UUID) {
                        if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
                                sc.SetState(SCE_C_DEFAULT);
                        }
                }

                // Determine if a new state should be entered.
                if (sc.atLineStart) {
                        visibleChars = 0;
                }
                if (sc.state == SCE_C_DEFAULT) {
                        if (sc.Match('@', '\"')) {
                                sc.SetState(SCE_C_VERBATIM);
                                sc.Forward();
                        } else if (IsADigit(sc.ch) || (sc.ch == '.' && 
IsADigit(sc.chNext))) {
                                if (lastWordWasUUID) {
                                        sc.SetState(SCE_C_UUID);
                                        lastWordWasUUID = false;
                                } else {
                                        sc.SetState(SCE_C_NUMBER);
                                }
                        } else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
                                if (lastWordWasUUID) {
                                        sc.SetState(SCE_C_UUID);
                                        lastWordWasUUID = false;
                                } else {
                                        sc.SetState(SCE_C_IDENTIFIER);
                                }
                        } else if (sc.Match('/', '*')) {
                                if (sc.Match("/**") || sc.Match("/*!")) {       
// Support of Qt/Doxygen doc. style
                                        sc.SetState(SCE_C_COMMENTDOC);
                                } else {
                                        sc.SetState(SCE_C_COMMENT);
                                }
                                sc.Forward();   // Eat the * so it isn't used 
for the end of the comment
                        } else if (sc.Match('/', '/')) {
                                if ((sc.Match("///") && !sc.Match("////")) || 
sc.Match("//!"))
                                        // Support of Qt/Doxygen doc. style
                                        sc.SetState(SCE_C_COMMENTLINEDOC);
                                else
                                        sc.SetState(SCE_C_COMMENTLINE);
                        } else if (sc.ch == '/' && 
IsOKBeforeRE(chPrevNonWhite)) {
                                sc.SetState(SCE_C_REGEX);       // JavaScript's 
RegEx
                        } else if (sc.ch == '\"') {
                                sc.SetState(SCE_C_STRING);
                        } else if (sc.ch == '\'') {
                                sc.SetState(SCE_C_CHARACTER);
                        } else if (sc.ch == '#' && visibleChars == 0) {
                                // Preprocessor commands are alone on their line
                                sc.SetState(SCE_C_PREPROCESSOR);
                                // Skip whitespace between # and preprocessor 
word
                                do {
                                        sc.Forward();
                                } while ((sc.ch == ' ' || sc.ch == '\t') && 
sc.More());
                                if (sc.atLineEnd) {
                                        sc.SetState(SCE_C_DEFAULT);
                                }
                        } else if (isoperator(static_cast<char>(sc.ch))) {
                                sc.SetState(SCE_C_OPERATOR);
                        }
                }

                if (sc.atLineEnd) {
                        // Reset states to begining of colourise so no surprises
                        // if different sets of lines lexed.
                        chPrevNonWhite = ' ';
                        visibleChars = 0;
                        lastWordWasUUID = false;
                }
                if (!IsASpace(sc.ch)) {
                        chPrevNonWhite = sc.ch;
                        visibleChars++;
                }
        }
        sc.Complete();
}

static bool IsStreamCommentStyle(int style) {
        return style == SCE_C_COMMENT ||
               style == SCE_C_COMMENTDOC ||
               style == SCE_C_COMMENTDOCKEYWORD ||
               style == SCE_C_COMMENTDOCKEYWORDERROR;
}

// Store both the current line's fold level and the next lines in the
// level store to make it easy to pick up with each increment
// and to make it possible to fiddle the current level for "} else {".
static void FoldNoBoxCppDoc(unsigned int startPos, int length, int initStyle,
                            Accessor &styler) {
        bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
        bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
        bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
        bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
        unsigned int endPos = startPos + length;
        int visibleChars = 0;
        int lineCurrent = styler.GetLine(startPos);
        int levelCurrent = SC_FOLDLEVELBASE;
        if (lineCurrent > 0)
                levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
        int levelMinCurrent = levelCurrent;
        int levelNext = levelCurrent;
        char chNext = styler[startPos];
        int styleNext = styler.StyleAt(startPos);
        int style = initStyle;
        for (unsigned int i = startPos; i < endPos; i++) {
                char ch = chNext;
                chNext = styler.SafeGetCharAt(i + 1);
                int stylePrev = style;
                style = styleNext;
                styleNext = styler.StyleAt(i + 1);
                bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
                if (foldComment && IsStreamCommentStyle(style)) {
                        if (!IsStreamCommentStyle(stylePrev)) {
                                levelNext++;
                        } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
                                // Comments don't end at end of line and the 
next character may be unstyled.
                                levelNext--;
                        }
                }
                if (foldComment && (style == SCE_C_COMMENTLINE)) {
                        if ((ch == '/') && (chNext == '/')) {
                                char chNext2 = styler.SafeGetCharAt(i + 2);
                                if (chNext2 == '{') {
                                        levelNext++;
                                } else if (chNext2 == '}') {
                                        levelNext--;
                                }
                        }
                }
                if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) {
                        if (ch == '#') {
                                unsigned int j = i + 1;
                                while ((j < endPos) && 
IsASpaceOrTab(styler.SafeGetCharAt(j))) {
                                        j++;
                                }
                                if (styler.Match(j, "region") || 
styler.Match(j, "if")) {
                                        levelNext++;
                                } else if (styler.Match(j, "end")) {
                                        levelNext--;
                                }
                        }
                }
                if (style == SCE_C_OPERATOR) {
                        if (ch == '{') {
                                // Measure the minimum before a '{' to allow
                                // folding on "} else {"
                                if (levelMinCurrent > levelNext) {
                                        levelMinCurrent = levelNext;
                                }
                                levelNext++;
                        } else if (ch == '}') {
                                levelNext--;
                        }
                }
                if (atEOL) {
                        int levelUse = levelCurrent;
                        if (foldAtElse) {
                                levelUse = levelMinCurrent;
                        }
                        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);
                        }
                        lineCurrent++;
                        levelCurrent = levelNext;
                        levelMinCurrent = levelCurrent;
                        visibleChars = 0;
                }
                if (!isspacechar(ch))
                        visibleChars++;
        }
}

static void FoldCppDoc(unsigned int startPos, int length, int initStyle, 
WordList *[],
                       Accessor &styler) {
        FoldNoBoxCppDoc(startPos, length, initStyle, styler);
}

static const char * const cppWordLists[] = {
            "Primary keywords and identifiers",
            "Secondary keywords and identifiers",
            "Documentation comment keywords",
            "Unused",
            "Global classes and typedefs",
            0,
        };

static void ColouriseCppDocSensitive(unsigned int startPos, int length, int 
initStyle, WordList *keywordlists[],
                                     Accessor &styler) {
        ColouriseCppDoc(startPos, length, initStyle, keywordlists, styler, 
true);
}

static void ColouriseCppDocInsensitive(unsigned int startPos, int length, int 
initStyle, WordList *keywordlists[],
                                       Accessor &styler) {
        ColouriseCppDoc(startPos, length, initStyle, keywordlists, styler, 
false);
}

LexerModule lmCPP(SCLEX_CPP, ColouriseCppDocSensitive, "cpp", FoldCppDoc, 
cppWordLists);
LexerModule lmCPPNoCase(SCLEX_CPPNOCASE, ColouriseCppDocInsensitive, 
"cppnocase", FoldCppDoc, cppWordLists);
LexerModule lmTCL(SCLEX_TCL, ColouriseCppDocSensitive, "tcl", FoldCppDoc, 
cppWordLists);
// Scintilla source code edit control
/** @file LexLua.cxx
 ** Lexer for Lua language.
 **
 ** Written by Paul Winwood.
 ** Folder by Alexey Yutkin.
 ** Modified by Marcos E. Wurzius & Philippe Lhoste
 **/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

// Extended to accept accented characters
static inline bool IsAWordChar(int ch) {
        return ch >= 0x80 ||
               (isalnum(ch) || ch == '.' || ch == '_');
}

static inline bool IsAWordStart(int ch) {
        return ch >= 0x80 ||
               (isalpha(ch) || ch == '_');
}

static inline bool IsANumberChar(int ch) {
        // Not exactly following number definition (several dots are seen as 
OK, etc.)
        // but probably enough in most cases.
        return (ch < 0x80) &&
                (isdigit(ch) || toupper(ch) == 'E' ||
             ch == '.' || ch == '-' || ch == '+');
}

static inline bool IsLuaOperator(int ch) {
        if (ch >= 0x80 || 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 == '>' || ch == ',' ||
                ch == '.' || ch == '^' || ch == '%' || ch == ':') {
                return true;
        }
        return false;
}

static void ColouriseLuaDoc(
        unsigned int startPos,
        int length,
        int initStyle,
        WordList *keywordlists[],
        Accessor &styler) {

        WordList &keywords = *keywordlists[0];
        WordList &keywords2 = *keywordlists[1];
        WordList &keywords3 = *keywordlists[2];
        WordList &keywords4 = *keywordlists[3];
        WordList &keywords5 = *keywordlists[4];
        WordList &keywords6 = *keywordlists[5];
        WordList &keywords7 = *keywordlists[6];
        WordList &keywords8 = *keywordlists[7];

        int currentLine = styler.GetLine(startPos);
        // Initialize the literal string [[ ... ]] nesting level, if we are 
inside such a string.
        int literalStringLevel = 0;
        if (initStyle == SCE_LUA_LITERALSTRING) {
                literalStringLevel = styler.GetLineState(currentLine - 1);
        }
        // Initialize the block comment --[[ ... ]] nesting level, if we are 
inside such a comment
        int blockCommentLevel = 0;
        if (initStyle == SCE_LUA_COMMENT) {
                blockCommentLevel = styler.GetLineState(currentLine - 1);
        }

        // Do not leak onto next line
        if (initStyle == SCE_LUA_STRINGEOL || initStyle == SCE_LUA_COMMENTLINE 
|| initStyle == SCE_LUA_PREPROCESSOR) {
                initStyle = SCE_LUA_DEFAULT;
        }

        StyleContext sc(startPos, length, initStyle, styler);
        if (startPos == 0 && sc.ch == '#') {
                // shbang line: # is a comment only if first char of the script
                sc.SetState(SCE_LUA_COMMENTLINE);
        }
        for (; sc.More(); sc.Forward()) {
                if (sc.atLineEnd) {
                        // Update the line state, so it can be seen by next line
                        currentLine = styler.GetLine(sc.currentPos);
                        switch (sc.state) {
                        case SCE_LUA_LITERALSTRING:
                                // Inside a literal string, we set the line 
state
                                styler.SetLineState(currentLine, 
literalStringLevel);
                                break;
                        case SCE_LUA_COMMENT:   // Block comment
                                // Inside a block comment, we set the line state
                                styler.SetLineState(currentLine, 
blockCommentLevel);
                                break;
                        default:
                                // Reset the line state
                                styler.SetLineState(currentLine, 0);
                                break;
                        }
                }
                if (sc.atLineStart && (sc.state == SCE_LUA_STRING)) {
                        // Prevent SCE_LUA_STRINGEOL from leaking back to 
previous line
                        sc.SetState(SCE_LUA_STRING);
                }

                // Handle string line continuation
                if ((sc.state == SCE_LUA_STRING || sc.state == 
SCE_LUA_CHARACTER) &&
                        sc.ch == '\\') {
                        if (sc.chNext == '\n' || sc.chNext == '\r') {
                                sc.Forward();
                                if (sc.ch == '\r' && sc.chNext == '\n') {
                                        sc.Forward();
                                }
                                continue;
                        }
                }

                // Determine if the current state should terminate.
                if (sc.state == SCE_LUA_OPERATOR) {
                        sc.SetState(SCE_LUA_DEFAULT);
                } else if (sc.state == SCE_LUA_NUMBER) {
                        // We stop the number definition on non-numerical 
non-dot non-eE non-sign char
                        if (!IsANumberChar(sc.ch)) {
                                sc.SetState(SCE_LUA_DEFAULT);
                        }
                } else if (sc.state == SCE_LUA_IDENTIFIER) {
                        if (!IsAWordChar(sc.ch) || sc.Match('.', '.')) {
                                char s[100];
                                sc.GetCurrent(s, sizeof(s));
                                if (keywords.InList(s)) {
                                        sc.ChangeState(SCE_LUA_WORD);
                                } else if (keywords2.InList(s)) {
                                        sc.ChangeState(SCE_LUA_WORD2);
                                } else if (keywords3.InList(s)) {
                                        sc.ChangeState(SCE_LUA_WORD3);
                                } else if (keywords4.InList(s)) {
                                        sc.ChangeState(SCE_LUA_WORD4);
                                } else if (keywords5.InList(s)) {
                                        sc.ChangeState(SCE_LUA_WORD5);
                                } else if (keywords6.InList(s)) {
                                        sc.ChangeState(SCE_LUA_WORD6);
                                } else if (keywords6.InList(s)) {
                                        sc.ChangeState(SCE_LUA_WORD6);
                                } else if (keywords7.InList(s)) {
                                        sc.ChangeState(SCE_LUA_WORD7);
                                } else if (keywords8.InList(s)) {
                                        sc.ChangeState(SCE_LUA_WORD8);
                                }
                                sc.SetState(SCE_LUA_DEFAULT);
                        }
                } else if (sc.state == SCE_LUA_COMMENTLINE) {
                        if (sc.atLineEnd) {
                                sc.ForwardSetState(SCE_LUA_DEFAULT);
                        }
                } else if (sc.state == SCE_LUA_PREPROCESSOR) {
                        if (sc.atLineEnd) {
                                sc.ForwardSetState(SCE_LUA_DEFAULT);
                        }
                } else if (sc.state == SCE_LUA_STRING) {
                        if (sc.ch == '\\') {
                                if (sc.chNext == '\"' || sc.chNext == '\'' || 
sc.chNext == '\\') {
                                        sc.Forward();
                                }
                        } else if (sc.ch == '\"') {
                                sc.ForwardSetState(SCE_LUA_DEFAULT);
                        } else if (sc.atLineEnd) {
                                sc.ChangeState(SCE_LUA_STRINGEOL);
                                sc.ForwardSetState(SCE_LUA_DEFAULT);
                        }
                } else if (sc.state == SCE_LUA_CHARACTER) {
                        if (sc.ch == '\\') {
                                if (sc.chNext == '\"' || sc.chNext == '\'' || 
sc.chNext == '\\') {
                                        sc.Forward();
                                }
                        } else if (sc.ch == '\'') {
                                sc.ForwardSetState(SCE_LUA_DEFAULT);
                        } else if (sc.atLineEnd) {
                                sc.ChangeState(SCE_LUA_STRINGEOL);
                                sc.ForwardSetState(SCE_LUA_DEFAULT);
                        }
                } else if (sc.state == SCE_LUA_LITERALSTRING) {
                        if (sc.Match('[', '[')) {
                                literalStringLevel++;
                                sc.Forward();
                                sc.SetState(SCE_LUA_LITERALSTRING);
                        } else if (sc.Match(']', ']') && literalStringLevel > 
0) {
                                literalStringLevel--;
                                sc.Forward();
                                if (literalStringLevel == 0) {
                                        sc.ForwardSetState(SCE_LUA_DEFAULT);
                                }
                        }
                } else if (sc.state == SCE_LUA_COMMENT) {       // Lua 5.0's 
block comment
                        if (sc.Match('[', '[')) {
                                blockCommentLevel++;
                                sc.Forward();
                        } else if (sc.Match(']', ']') && blockCommentLevel > 0) 
{
                                blockCommentLevel--;
                                sc.Forward();
                                if (blockCommentLevel == 0) {
                                        sc.ForwardSetState(SCE_LUA_DEFAULT);
                                }
                        }
                }

                // Determine if a new state should be entered.
                if (sc.state == SCE_LUA_DEFAULT) {
                        if (IsADigit(sc.ch) || (sc.ch == '.' && 
IsADigit(sc.chNext))) {
                                sc.SetState(SCE_LUA_NUMBER);
                        } else if (IsAWordStart(sc.ch)) {
                                sc.SetState(SCE_LUA_IDENTIFIER);
                        } else if (sc.Match('\"')) {
                                sc.SetState(SCE_LUA_STRING);
                        } else if (sc.Match('\'')) {
                                sc.SetState(SCE_LUA_CHARACTER);
                        } else if (sc.Match('[', '[')) {
                                literalStringLevel = 1;
                                sc.SetState(SCE_LUA_LITERALSTRING);
                                sc.Forward();
                        } else if (sc.Match("--[[")) {  // Lua 5.0's block 
comment
                                blockCommentLevel = 1;
                                sc.SetState(SCE_LUA_COMMENT);
                                sc.Forward(3);
                        } else if (sc.Match('-', '-')) {
                                sc.SetState(SCE_LUA_COMMENTLINE);
                                sc.Forward();
                        } else if (sc.atLineStart && sc.Match('$')) {
                                sc.SetState(SCE_LUA_PREPROCESSOR);      // 
Obsolete since Lua 4.0, but still in old code
                        } else if (IsLuaOperator(static_cast<char>(sc.ch))) {
                                sc.SetState(SCE_LUA_OPERATOR);
                        }
                }
        }
        sc.Complete();
}

static void FoldLuaDoc(unsigned int startPos, int length, int /* initStyle */, 
WordList *[],
                       Accessor &styler) {
        unsigned int lengthDoc = startPos + length;
        int visibleChars = 0;
        int lineCurrent = styler.GetLine(startPos);
        int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
        int levelCurrent = levelPrev;
        char chNext = styler[startPos];
        bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
        int styleNext = styler.StyleAt(startPos);
        char s[10];

        for (unsigned int i = startPos; i < lengthDoc; i++) {
                char ch = chNext;
                chNext = styler.SafeGetCharAt(i + 1);
                int style = styleNext;
                styleNext = styler.StyleAt(i + 1);
                bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
                if (style == SCE_LUA_WORD) {
                        if (ch == 'i' || ch == 'd' || ch == 'f' || ch == 'e' || 
ch == 'r' || ch == 'u') {
                                for (unsigned int j = 0; j < 8; j++) {
                                        if (!iswordchar(styler[i + j])) {
                                                break;
                                        }
                                        s[j] = styler[i + j];
                                        s[j + 1] = '\0';
                                }

                                if ((strcmp(s, "if") == 0) || (strcmp(s, "do") 
== 0) || (strcmp(s, "function") == 0) || (strcmp(s, "repeat") == 0)) {
                                        levelCurrent++;
                                }
                                if ((strcmp(s, "end") == 0) || (strcmp(s, 
"elseif") == 0) || (strcmp(s, "until") == 0)) {
                                        levelCurrent--;
                                }
                        }
                } else if (style == SCE_LUA_OPERATOR) {
                        if (ch == '{' || ch == '(') {
                                levelCurrent++;
                        } else if (ch == '}' || ch == ')') {
                                levelCurrent--;
                        }
                } else if (style == SCE_LUA_LITERALSTRING || style == 
SCE_LUA_COMMENT) {
                        if (ch == '[') {
                                levelCurrent++;
                        } else if (ch == ']') {
                                levelCurrent--;
                        }
                }

                if (atEOL) {
                        int lev = levelPrev;
                        if (visibleChars == 0 && foldCompact) {
                                lev |= SC_FOLDLEVELWHITEFLAG;
                        }
                        if ((levelCurrent > levelPrev) && (visibleChars > 0)) {
                                lev |= SC_FOLDLEVELHEADERFLAG;
                        }
                        if (lev != styler.LevelAt(lineCurrent)) {
                                styler.SetLevel(lineCurrent, lev);
                        }
                        lineCurrent++;
                        levelPrev = levelCurrent;
                        visibleChars = 0;
                }
                if (!isspacechar(ch)) {
                        visibleChars++;
                }
        }
        // Fill in the real level of the next line, keeping the current flags 
as they will be filled in later

        int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
        styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const luaWordListDesc[] = {
        "Keywords",
        "Basic functions",
        "String, (table) & math functions",
        "(coroutines), I/O & system facilities",
        "user1",
        "user2",
        "user3",
        "user4",
        0
};

LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc, 
luaWordListDesc);
_______________________________________________
Scintilla-interest mailing list
[email protected]
http://mailman.lyra.org/mailman/listinfo/scintilla-interest

Reply via email to