mirror of
				https://github.com/notepad-plus-plus/notepad-plus-plus.git
				synced 2025-11-04 05:23:56 +01:00 
			
		
		
		
	Update with https://www.scintilla.org/scintilla521.zip https://www.scintilla.org/lexilla515.zip - fix setting to bring Scintilla::PositionCR from ScintillaStructures.h inline with Sci_Position.h Sci_PositionCR - add workaround to enable lexer for searchResult commented out SCI_SETILEXER call on searchResult to get one result which is correctly handled by the lexer, added comment about the current problem with property @MarkingsStruct which seems to disappear after call to SCI_SETILEXER or CreateLexer - corrected usage of ObjC lexer - removed unnecessary filter stuff - use own sections for scintilla and lexilla build targets and allow parallel builds - as libscilex is no longer existing, changed to libscintilla - adapt makefiles and cmake - use VS2019 - started simple changes for createlexer adaptations, nullpointercheck missing on return of lexer name from deprecated LexerNameFromID -> undefined behaviour - movement from id -> lexer name, mostly done via LexerNameFromID + switching off corresponding compiler warning - changed to SCI_SETILEXER from SCI_SETLEXER, SCI_SETLEXERLANGUAGE needs to be corrected, see Scintilla5Migration.html - just commented out: SCI_LOADLEXERLIBRARY Fix #10504, close #11419
		
			
				
	
	
		
			475 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			475 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Scintilla source code edit control
 | 
						|
/** @file LexKVIrc.cxx
 | 
						|
 ** Lexer for KVIrc script.
 | 
						|
 **/
 | 
						|
// Copyright 2013 by OmegaPhil <OmegaPhil+scintilla@gmail.com>, based in
 | 
						|
// part from LexPython Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
 | 
						|
// and LexCmake Copyright 2007 by Cristian Adam <cristian [dot] adam [at] gmx [dot] net>
 | 
						|
 | 
						|
// The License.txt file describes the conditions under which this software may be distributed.
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <assert.h>
 | 
						|
#include <ctype.h>
 | 
						|
 | 
						|
#include <string>
 | 
						|
#include <string_view>
 | 
						|
 | 
						|
#include "ILexer.h"
 | 
						|
#include "Scintilla.h"
 | 
						|
#include "SciLexer.h"
 | 
						|
 | 
						|
#include "WordList.h"
 | 
						|
#include "LexAccessor.h"
 | 
						|
#include "Accessor.h"
 | 
						|
#include "StyleContext.h"
 | 
						|
#include "CharacterSet.h"
 | 
						|
#include "LexerModule.h"
 | 
						|
 | 
						|
using namespace Lexilla;
 | 
						|
 | 
						|
 | 
						|
/* KVIrc Script syntactic rules: http://www.kvirc.net/doc/doc_syntactic_rules.html */
 | 
						|
 | 
						|
/* Utility functions */
 | 
						|
static inline bool IsAWordChar(int ch) {
 | 
						|
 | 
						|
    /* Keyword list includes modules, i.e. words including '.', and
 | 
						|
     * alias namespaces include ':' */
 | 
						|
    return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.'
 | 
						|
            || ch == ':');
 | 
						|
}
 | 
						|
static inline bool IsAWordStart(int ch) {
 | 
						|
 | 
						|
    /* Functions (start with '$') are treated separately to keywords */
 | 
						|
    return (ch < 0x80) && (isalnum(ch) || ch == '_' );
 | 
						|
}
 | 
						|
 | 
						|
/* Interface function called by Scintilla to request some text to be
 | 
						|
 syntax highlighted */
 | 
						|
static void ColouriseKVIrcDoc(Sci_PositionU startPos, Sci_Position length,
 | 
						|
                              int initStyle, WordList *keywordlists[],
 | 
						|
                              Accessor &styler)
 | 
						|
{
 | 
						|
    /* Fetching style context */
 | 
						|
    StyleContext sc(startPos, length, initStyle, styler);
 | 
						|
 | 
						|
    /* Accessing keywords and function-marking keywords */
 | 
						|
    WordList &keywords = *keywordlists[0];
 | 
						|
    WordList &functionKeywords = *keywordlists[1];
 | 
						|
 | 
						|
    /* Looping for all characters - only automatically moving forward
 | 
						|
     * when asked for (transitions leaving strings and keywords do this
 | 
						|
     * already) */
 | 
						|
    bool next = true;
 | 
						|
    for( ; sc.More(); next ? sc.Forward() : (void)0 )
 | 
						|
    {
 | 
						|
        /* Resetting next */
 | 
						|
        next = true;
 | 
						|
 | 
						|
        /* Dealing with different states */
 | 
						|
        switch (sc.state)
 | 
						|
        {
 | 
						|
            case SCE_KVIRC_DEFAULT:
 | 
						|
 | 
						|
                /* Detecting single-line comments
 | 
						|
                 * Unfortunately KVIrc script allows raw '#<channel
 | 
						|
                 * name>' to be used, and appending # to an array returns
 | 
						|
                 * its length...
 | 
						|
                 * Going for a compromise where single line comments not
 | 
						|
                 * starting on a newline are allowed in all cases except
 | 
						|
                 * when they are preceeded with an opening bracket or comma
 | 
						|
                 * (this will probably be the most common style a valid
 | 
						|
                 * string-less channel name will be used with), with the
 | 
						|
                 * array length case included
 | 
						|
                 */
 | 
						|
                if (
 | 
						|
                    (sc.ch == '#' && sc.atLineStart) ||
 | 
						|
                    (sc.ch == '#' && (
 | 
						|
                        sc.chPrev != '(' && sc.chPrev != ',' &&
 | 
						|
                        sc.chPrev != ']')
 | 
						|
                    )
 | 
						|
                )
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_COMMENT);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                /* Detecting multi-line comments */
 | 
						|
                if (sc.Match('/', '*'))
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_COMMENTBLOCK);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                /* Detecting strings */
 | 
						|
                if (sc.ch == '"')
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_STRING);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                /* Detecting functions */
 | 
						|
                if (sc.ch == '$')
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_FUNCTION);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                /* Detecting variables */
 | 
						|
                if (sc.ch == '%')
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_VARIABLE);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                /* Detecting numbers - isdigit is unsafe as it does not
 | 
						|
                 * validate, use CharacterSet.h functions */
 | 
						|
                if (IsADigit(sc.ch))
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_NUMBER);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                /* Detecting words */
 | 
						|
                if (IsAWordStart(sc.ch) && IsAWordChar(sc.chNext))
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_WORD);
 | 
						|
                    sc.Forward();
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                /* Detecting operators */
 | 
						|
                if (isoperator(sc.ch))
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_OPERATOR);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                break;
 | 
						|
 | 
						|
            case SCE_KVIRC_COMMENT:
 | 
						|
 | 
						|
                /* Breaking out of single line comment when a newline
 | 
						|
                 * is introduced */
 | 
						|
                if (sc.ch == '\r' || sc.ch == '\n')
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_DEFAULT);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                break;
 | 
						|
 | 
						|
            case SCE_KVIRC_COMMENTBLOCK:
 | 
						|
 | 
						|
                /* Detecting end of multi-line comment */
 | 
						|
                if (sc.Match('*', '/'))
 | 
						|
                {
 | 
						|
                    // Moving the current position forward two characters
 | 
						|
                    // so that '*/' is included in the comment
 | 
						|
                    sc.Forward(2);
 | 
						|
                    sc.SetState(SCE_KVIRC_DEFAULT);
 | 
						|
 | 
						|
                    /* Comment has been exited and the current position
 | 
						|
                     * moved forward, yet the new current character
 | 
						|
                     * has yet to be defined - loop without moving
 | 
						|
                     * forward again */
 | 
						|
                    next = false;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                break;
 | 
						|
 | 
						|
            case SCE_KVIRC_STRING:
 | 
						|
 | 
						|
                /* Detecting end of string - closing speechmarks */
 | 
						|
                if (sc.ch == '"')
 | 
						|
                {
 | 
						|
                    /* Allowing escaped speechmarks to pass */
 | 
						|
                    if (sc.chPrev == '\\')
 | 
						|
                        break;
 | 
						|
 | 
						|
                    /* Moving the current position forward to capture the
 | 
						|
                     * terminating speechmarks, and ending string */
 | 
						|
                    sc.ForwardSetState(SCE_KVIRC_DEFAULT);
 | 
						|
 | 
						|
                    /* String has been exited and the current position
 | 
						|
                     * moved forward, yet the new current character
 | 
						|
                     * has yet to be defined - loop without moving
 | 
						|
                     * forward again */
 | 
						|
                    next = false;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                /* Functions and variables are now highlighted in strings
 | 
						|
                 * Detecting functions */
 | 
						|
                if (sc.ch == '$')
 | 
						|
                {
 | 
						|
                    /* Allowing escaped functions to pass */
 | 
						|
                    if (sc.chPrev == '\\')
 | 
						|
                        break;
 | 
						|
 | 
						|
                    sc.SetState(SCE_KVIRC_STRING_FUNCTION);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                /* Detecting variables */
 | 
						|
                if (sc.ch == '%')
 | 
						|
                {
 | 
						|
                    /* Allowing escaped variables to pass */
 | 
						|
                    if (sc.chPrev == '\\')
 | 
						|
                        break;
 | 
						|
 | 
						|
                    sc.SetState(SCE_KVIRC_STRING_VARIABLE);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                /* Breaking out of a string when a newline is introduced */
 | 
						|
                if (sc.ch == '\r' || sc.ch == '\n')
 | 
						|
                {
 | 
						|
                    /* Allowing escaped newlines */
 | 
						|
                    if (sc.chPrev == '\\')
 | 
						|
                        break;
 | 
						|
 | 
						|
                    sc.SetState(SCE_KVIRC_DEFAULT);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                break;
 | 
						|
 | 
						|
            case SCE_KVIRC_FUNCTION:
 | 
						|
            case SCE_KVIRC_VARIABLE:
 | 
						|
 | 
						|
                /* Detecting the end of a function/variable (word) */
 | 
						|
                if (!IsAWordChar(sc.ch))
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_DEFAULT);
 | 
						|
 | 
						|
                    /* Word has been exited yet the current character
 | 
						|
                     * has yet to be defined - loop without moving
 | 
						|
                     * forward again */
 | 
						|
                    next = false;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                break;
 | 
						|
 | 
						|
            case SCE_KVIRC_STRING_FUNCTION:
 | 
						|
            case SCE_KVIRC_STRING_VARIABLE:
 | 
						|
 | 
						|
                /* A function or variable in a string
 | 
						|
                 * Detecting the end of a function/variable (word) */
 | 
						|
                if (!IsAWordChar(sc.ch))
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_STRING);
 | 
						|
 | 
						|
                    /* Word has been exited yet the current character
 | 
						|
                     * has yet to be defined - loop without moving
 | 
						|
                     * forward again */
 | 
						|
                    next = false;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                break;
 | 
						|
 | 
						|
            case SCE_KVIRC_NUMBER:
 | 
						|
 | 
						|
                /* Detecting the end of a number */
 | 
						|
                if (!IsADigit(sc.ch))
 | 
						|
                {
 | 
						|
                    sc.SetState(SCE_KVIRC_DEFAULT);
 | 
						|
 | 
						|
                    /* Number has been exited yet the current character
 | 
						|
                     * has yet to be defined - loop without moving
 | 
						|
                     * forward */
 | 
						|
                    next = false;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                break;
 | 
						|
 | 
						|
            case SCE_KVIRC_OPERATOR:
 | 
						|
 | 
						|
                /* Because '%' is an operator but is also the marker for
 | 
						|
                 * a variable, I need to always treat operators as single
 | 
						|
                 * character strings and therefore redo their detection
 | 
						|
                 * after every character */
 | 
						|
                sc.SetState(SCE_KVIRC_DEFAULT);
 | 
						|
 | 
						|
                /* Operator has been exited yet the current character
 | 
						|
                 * has yet to be defined - loop without moving
 | 
						|
                 * forward */
 | 
						|
                next = false;
 | 
						|
                break;
 | 
						|
 | 
						|
            case SCE_KVIRC_WORD:
 | 
						|
 | 
						|
                /* Detecting the end of a word */
 | 
						|
                if (!IsAWordChar(sc.ch))
 | 
						|
                {
 | 
						|
                    /* Checking if the word was actually a keyword -
 | 
						|
                     * fetching the current word, NULL-terminated like
 | 
						|
                     * the keyword list */
 | 
						|
                    char s[100];
 | 
						|
                    Sci_Position wordLen = sc.currentPos - styler.GetStartSegment();
 | 
						|
                    if (wordLen > 99)
 | 
						|
                        wordLen = 99;  /* Include '\0' in buffer */
 | 
						|
                    Sci_Position i;
 | 
						|
                    for( i = 0; i < wordLen; ++i )
 | 
						|
                    {
 | 
						|
                        s[i] = styler.SafeGetCharAt( styler.GetStartSegment() + i );
 | 
						|
                    }
 | 
						|
                    s[wordLen] = '\0';
 | 
						|
 | 
						|
                    /* Actually detecting keywords and fixing the state */
 | 
						|
                    if (keywords.InList(s))
 | 
						|
                    {
 | 
						|
                        /* The SetState call actually commits the
 | 
						|
                         * previous keyword state */
 | 
						|
                        sc.ChangeState(SCE_KVIRC_KEYWORD);
 | 
						|
                    }
 | 
						|
                    else if (functionKeywords.InList(s))
 | 
						|
                    {
 | 
						|
                        // Detecting function keywords and fixing the state
 | 
						|
                        sc.ChangeState(SCE_KVIRC_FUNCTION_KEYWORD);
 | 
						|
                    }
 | 
						|
 | 
						|
                    /* Transitioning to default and committing the previous
 | 
						|
                     * word state */
 | 
						|
                    sc.SetState(SCE_KVIRC_DEFAULT);
 | 
						|
 | 
						|
                    /* Word has been exited yet the current character
 | 
						|
                     * has yet to be defined - loop without moving
 | 
						|
                     * forward again */
 | 
						|
                    next = false;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* Indicating processing is complete */
 | 
						|
    sc.Complete();
 | 
						|
}
 | 
						|
 | 
						|
static void FoldKVIrcDoc(Sci_PositionU startPos, Sci_Position length, int /*initStyle - unused*/,
 | 
						|
                      WordList *[], Accessor &styler)
 | 
						|
{
 | 
						|
    /* Based on CMake's folder */
 | 
						|
 | 
						|
    /* Exiting if folding isnt enabled */
 | 
						|
    if ( styler.GetPropertyInt("fold") == 0 )
 | 
						|
        return;
 | 
						|
 | 
						|
    /* Obtaining current line number*/
 | 
						|
    Sci_Position currentLine = styler.GetLine(startPos);
 | 
						|
 | 
						|
    /* Obtaining starting character - indentation is done on a line basis,
 | 
						|
     * not character */
 | 
						|
    Sci_PositionU safeStartPos = styler.LineStart( currentLine );
 | 
						|
 | 
						|
    /* Initialising current level - this is defined as indentation level
 | 
						|
     * in the low 12 bits, with flag bits in the upper four bits.
 | 
						|
     * It looks like two indentation states are maintained in the returned
 | 
						|
     * 32bit value - 'nextLevel' in the most-significant bits, 'currentLevel'
 | 
						|
     * in the least-significant bits. Since the next level is the most
 | 
						|
     * up to date, this must refer to the current state of indentation.
 | 
						|
     * So the code bitshifts the old current level out of existence to
 | 
						|
     * get at the actual current state of indentation
 | 
						|
     * Based on the LexerCPP.cxx line 958 comment */
 | 
						|
    int currentLevel = SC_FOLDLEVELBASE;
 | 
						|
    if (currentLine > 0)
 | 
						|
        currentLevel = styler.LevelAt(currentLine - 1) >> 16;
 | 
						|
    int nextLevel = currentLevel;
 | 
						|
 | 
						|
    // Looping for characters in range
 | 
						|
    for (Sci_PositionU i = safeStartPos; i < startPos + length; ++i)
 | 
						|
    {
 | 
						|
        /* Folding occurs after syntax highlighting, meaning Scintilla
 | 
						|
         * already knows where the comments are
 | 
						|
         * Fetching the current state */
 | 
						|
        int state = styler.StyleAt(i) & 31;
 | 
						|
 | 
						|
        switch( styler.SafeGetCharAt(i) )
 | 
						|
        {
 | 
						|
            case '{':
 | 
						|
 | 
						|
                /* Indenting only when the braces are not contained in
 | 
						|
                 * a comment */
 | 
						|
                if (state != SCE_KVIRC_COMMENT &&
 | 
						|
                    state != SCE_KVIRC_COMMENTBLOCK)
 | 
						|
                    ++nextLevel;
 | 
						|
                break;
 | 
						|
 | 
						|
            case '}':
 | 
						|
 | 
						|
                /* Outdenting only when the braces are not contained in
 | 
						|
                 * a comment */
 | 
						|
                if (state != SCE_KVIRC_COMMENT &&
 | 
						|
                    state != SCE_KVIRC_COMMENTBLOCK)
 | 
						|
                    --nextLevel;
 | 
						|
                break;
 | 
						|
 | 
						|
            case '\n':
 | 
						|
            case '\r':
 | 
						|
 | 
						|
                /* Preparing indentation information to return - combining
 | 
						|
                 * current and next level data */
 | 
						|
                int lev = currentLevel | nextLevel << 16;
 | 
						|
 | 
						|
                /* If the next level increases the indent level, mark the
 | 
						|
                 * current line as a fold point - current level data is
 | 
						|
                 * in the least significant bits */
 | 
						|
                if (nextLevel > currentLevel )
 | 
						|
                    lev |= SC_FOLDLEVELHEADERFLAG;
 | 
						|
 | 
						|
                /* Updating indentation level if needed */
 | 
						|
                if (lev != styler.LevelAt(currentLine))
 | 
						|
                    styler.SetLevel(currentLine, lev);
 | 
						|
 | 
						|
                /* Updating variables */
 | 
						|
                ++currentLine;
 | 
						|
                currentLevel = nextLevel;
 | 
						|
 | 
						|
                /* Dealing with problematic Windows newlines -
 | 
						|
                 * incrementing to avoid the extra newline breaking the
 | 
						|
                 * fold point */
 | 
						|
                if (styler.SafeGetCharAt(i) == '\r' &&
 | 
						|
                    styler.SafeGetCharAt(i + 1) == '\n')
 | 
						|
                    ++i;
 | 
						|
                break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* At this point the data has ended, so presumably the end of the line?
 | 
						|
     * Preparing indentation information to return - combining current
 | 
						|
     * and next level data */
 | 
						|
    int lev = currentLevel | nextLevel << 16;
 | 
						|
 | 
						|
    /* If the next level increases the indent level, mark the current
 | 
						|
     * line as a fold point - current level data is in the least
 | 
						|
     * significant bits */
 | 
						|
    if (nextLevel > currentLevel )
 | 
						|
        lev |= SC_FOLDLEVELHEADERFLAG;
 | 
						|
 | 
						|
    /* Updating indentation level if needed */
 | 
						|
    if (lev != styler.LevelAt(currentLine))
 | 
						|
        styler.SetLevel(currentLine, lev);
 | 
						|
}
 | 
						|
 | 
						|
/* Registering wordlists */
 | 
						|
static const char *const kvircWordListDesc[] = {
 | 
						|
	"primary",
 | 
						|
	"function_keywords",
 | 
						|
	0
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/* Registering functions and wordlists */
 | 
						|
LexerModule lmKVIrc(SCLEX_KVIRC, ColouriseKVIrcDoc, "kvirc", FoldKVIrcDoc,
 | 
						|
                    kvircWordListDesc);
 |