play around with Scintilla and Lexilla

This commit is contained in:
2024-07-02 23:47:26 +08:00
parent d7c71f41b2
commit 727a2ec214
992 changed files with 281111 additions and 195 deletions

31
3rdparty/lexilla532/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,31 @@
# this file is actually the CMake version of Lexilla.pro
cmake_minimum_required(VERSION 3.10)
project(lexilla)
add_library(${PROJECT_NAME} SHARED)
set(CMAKE_CXX_STANDARD 17)
file(GLOB_RECURSE SRCS CONFIGURE_DEPENDS
# main library binding
"${CMAKE_CURRENT_SOURCE_DIR}/lexilla/include/Lexilla.h"
"${CMAKE_CURRENT_SOURCE_DIR}/lexilla/src/Lexilla.cxx"
# lexlib
"${CMAKE_CURRENT_SOURCE_DIR}/lexilla/lexlib/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/lexilla/lexlib/*.cxx"
# lexers
"${CMAKE_CURRENT_SOURCE_DIR}/lexilla/lexers/Lex*.cxx"
)
target_sources(${PROJECT_NAME}
PRIVATE
${SRCS}
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/lexilla/include
${CMAKE_CURRENT_SOURCE_DIR}/lexilla/lexlib
${CMAKE_CURRENT_SOURCE_DIR}/../scintilla550/scintilla/include
)

17
3rdparty/lexilla532/README.md vendored Normal file
View File

@ -0,0 +1,17 @@
# About Lexilla
## Source
The vendored Lexilla source code is fetched from their official website [^1]. Version is 5.3.2. All vendored code are inside the `scintilla` folder.
[^1]: https://www.scintilla.org/LexillaDownload.html
## How to update
To update the vendored code to the newer version, do the following steps.
1. Download the ZIP archive of the new version, unzip it and replace the `lexilla` folder.
2. Reconfigure project, start to build, and see if it fails. If so, review the change of `Lexilla.pro` and see if we need to update the `CMakeLists.txt` in this folder (along with this `README.md` file).
3. Done, we can commit the change now.
The folder name that this sub-project lives at currently indicates the Lexilla version that we uses. If updated, consider also update the folder name as well.

View File

@ -0,0 +1,84 @@
* -text
**.cxx text
**.cpp text
**.c text
**.h text
**.hpp text
**.m text
**.mm text
**.iface text
**.template text
**.mk text
**.py text
**.rc text
**.css text
**.html text
**.bat text
**.bsh text
**.zsh text
**.mak text
**.def text
**.manifest text
**.properties text
**.props text
**.session text
**.styled text
**.folded text
**.adoc text
**.asp text
**.aspx text
**.php text
**.vb text
**.asm text
**.cob text
**.cmake text
**.d text
**.diff text
**.erl text
**.f text
**.gd text
**.gui text
**.iss text
**.jl text
**.json text
**.lua text
**.m3 text
**.matlab text
**.ml text
**.nim text
**.octave text
**.pl text
**.p6 text
**.ps1 text
**.r text
**.rb text
**.rs text
**.sql text
**.tcl text
**.tsql text
**.err text
**.mms text
**.tex text
**.fs text
**.vh text
**.vhd text
**.x12 text
**.yaml text
**.md text
**.txt text
**.pch text
**.hg* text
**.dsp text
**.pbxproj text
**.plist text
**.xcworkspacedata text
**.pro text
**.gen text
**makefile text
**.bmp binary
**.cur binary
**.ico binary
**.jpg binary
**.png binary
**.sh text eol=lf
tgzsrc text eol=lf

View File

@ -0,0 +1,33 @@
name: "Build and check Lexilla on macOS"
on: [push]
jobs:
build:
runs-on: macos-11
strategy:
matrix:
cpp_compiler: [clang++]
steps:
- uses: actions/checkout@v4
- name: Install Scintilla source
run: |
(cd .. && wget --no-verbose https://www.scintilla.org/scintilla500.zip)
(cd .. && unzip scintilla500.zip)
- name: Unit Test
run: (cd test/unit && make DEBUG=1 CXX=${{matrix.cpp_compiler}} test)
- name: Build Lexilla
run: (cd src && make DEBUG=1 CXX=${{matrix.cpp_compiler}})
- uses: actions/upload-artifact@v4
with:
name: liblexilla.dylib
path: bin/liblexilla.dylib
- name: Test lexing and folding
run: (cd test && make DEBUG=1 CXX=${{matrix.cpp_compiler}} test)
- name: CheckLexilla C Example
run: (cd examples/CheckLexilla && make DEBUG=1 check)
- name: SimpleLexer Example
run: (cd examples/SimpleLexer && make DEBUG=1 CXX=${{matrix.cpp_compiler}} check)

View File

@ -0,0 +1,53 @@
name: "Build and check Lexilla on Win32 with Visual C++"
on: [push]
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Preparing nmake
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: Install Scintilla source
run: |
pwd
cd ..
curl -O https://www.scintilla.org/scintilla500.zip
ls
7z x scintilla500.zip
cd lexilla
- name: Unit Test
run: |
cd test/unit
nmake -f test.mak DEBUG=1 test
cd ../..
- name: Build Lexilla
run: |
cd src
nmake -f lexilla.mak DEBUG=1
cd ..
- uses: actions/upload-artifact@v4
with:
name: lexilla.dll
path: bin/lexilla.dll
- name: Test lexing and folding
run: |
cd test
nmake -f testlexers.mak DEBUG=1 test
cd ..
- name: CheckLexilla C Example
run: |
cd examples/CheckLexilla
cl CheckLexilla.c -I ../../include -Fe: CheckLexilla
.\CheckLexilla.exe
cd ../..
- name: SimpleLexer Example
run: |
cd examples/SimpleLexer
cl -std:c++17 -EHsc -LD -I ../../../scintilla/include -I ../../include -I ../../lexlib SimpleLexer.cxx ../../lexlib/*.cxx
cd ../..

View File

@ -0,0 +1,34 @@
name: "Build and check Lexilla on Linux"
on: [push]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
cpp_compiler: [g++, clang++]
steps:
- uses: actions/checkout@v4
- name: Install Scintilla source
run: |
(cd .. && wget --no-verbose https://www.scintilla.org/scintilla500.zip)
(cd .. && unzip scintilla500.zip)
- name: Unit Test
run: (cd test/unit && make DEBUG=1 CXX=${{matrix.cpp_compiler}} test)
- name: Build Lexilla
run: (cd src && make DEBUG=1 CXX=${{matrix.cpp_compiler}})
- uses: actions/upload-artifact@v4
with:
name: liblexilla-${{matrix.cpp_compiler}}.so
path: bin/liblexilla.so
overwrite: true
- name: Test lexing and folding
run: (cd test && make DEBUG=1 CXX=${{matrix.cpp_compiler}} test)
- name: CheckLexilla C Example
run: (cd examples/CheckLexilla && make DEBUG=1 check)
- name: SimpleLexer Example
run: (cd examples/SimpleLexer && make DEBUG=1 CXX=${{matrix.cpp_compiler}} check)

71
3rdparty/lexilla532/lexilla/.gitignore vendored Normal file
View File

@ -0,0 +1,71 @@
*.o
*.a
*.lib
*.obj
*.iobj
__pycache__
*.pyc
*.dll
*.so
*.dylib
*.framework
*.pyd
*.exe
*.exp
*.lib
*.pdb
*.ipdb
*.res
*.bak
*.sbr
*.suo
*.aps
*.sln
*.vcxproj.*
*.idb
*.bsc
*.intermediate.manifest
*.lastbuildstate
*.nativecodeanalysis.xml
*.cache
*.ilk
*.ncb
*.tlog
*.sdf
gtk/*.plist
win32/*.plist
*.opt
*.plg
*.pbxbtree
*.mode1v3
*.pbxuser
*.pbproj
*.tgz
*.log
*.xcbkptlist
*.xcuserstate
xcuserdata/
*.xcsettings
xcschememanagement.plist
.DS_Store
test/TestLexers
Release
Debug
x64
ARM64
cocoa/build
cocoa/ScintillaFramework/build
cocoa/ScintillaTest/build
macosx/SciTest/build
*.cppcheck
*.pro.user
.qmake.stash
cov-int
.vs
meson-private
meson-logs
build.ninja
.ninja*
compile_commands.json
.vscode/
VTune Profiler Results/

42
3rdparty/lexilla532/lexilla/.travis.yml vendored Normal file
View File

@ -0,0 +1,42 @@
# Build Lexilla with gcc and clang on Linux, macOS, and Windows
# Test Lexilla with gcc and clang on Linux and macOS
# Windows has older versions of libraries so can't compile std::filesystem
# with gcc or std::string::starts_with with clang.
# On macOS, gcc is a synonym for clang so exclude gcc.
os:
- linux
- osx
- windows
dist: focal
osx_image: xcode12.3
language: cpp
jobs:
exclude:
- os: osx
compiler: gcc
install:
- cd ..
- wget --no-verbose https://www.scintilla.org/scintilla500.zip
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then 7z x scintilla500.zip ; else unzip scintilla500.zip ; fi
- cd lexilla
compiler:
- gcc
- clang
script:
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then MAKER="mingw32-make windir=1" ; else MAKER="make" ; fi
- (cd src && $MAKER DEBUG=1)
- cd test
- if [ "$TRAVIS_OS_NAME" != "windows" ]; then make DEBUG=1 test ; fi
- (cd unit && $MAKER DEBUG=1 test)
- cd ..
- cd examples
- (cd CheckLexilla && $MAKER DEBUG=1 check)
- (cd SimpleLexer && $MAKER DEBUG=1 check)
- cd ..

View File

@ -0,0 +1,42 @@
Lexilla is on GitHub at https://github.com/ScintillaOrg/lexilla
Bugs, fixes and features should be posted to the Issue Tracker
https://github.com/ScintillaOrg/lexilla/issues
Patches should include test cases. Add a test case file in
lexilla/test/examples/<language> and run the test program in
lexilla/test.
The result will be new files with ".styled.new" and ".folded.new"
appended containing lexing or folding results.
For lexing, there are brace surrounded style numbers for each style
start as markup:
{5}import{0} {11}contextlib{0}
For folding, there are 4 columns of folding results preceding the example text:
2 400 0 + --[[ coding:UTF-8
0 402 0 | comment ]]
See the test/README file for more explanation of the folding results.
To build lexilla and the tests with gcc there are Windows batch
and Unix shell files scripts/RunTest.bat scripts/RunTest.sh.
Check the result of the .new files and, if correct, rename replacing
".styled.new" with ".styled" and ".folded.new" with ".folded".
Run the tests again and success should be reported.
Include the .styled and .folded files in the patch.
Including test cases ensures that the change won't be undone by
other changes in the future and clarifies the intentions of the author.
Either send unified diffs (or patch files) or zip archives with whole files.
Mercurial/Git patch files are best as they include author information and commit
messages.
Questions should go to the scintilla-interest mailing list
https://groups.google.com/forum/#!forum/scintilla-interest
Code should follow the guidelines at
https://www.scintilla.org/SciCoding.html
Lexilla is on GitHub so use its facilities rather than SourceForge which is
the home of Scintilla.
The neilh @ scintilla.org account receives much spam and is only checked
occasionally. Almost all Scintilla mail should go to the mailing list.

20
3rdparty/lexilla532/lexilla/License.txt vendored Normal file
View File

@ -0,0 +1,20 @@
License for Lexilla, Scintilla, and SciTE
Copyright 1998-2021 by Neil Hodgson <neilh@scintilla.org>
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation.
NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS, IN NO EVENT SHALL NEIL HODGSON BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THIS SOFTWARE.

49
3rdparty/lexilla532/lexilla/README vendored Normal file
View File

@ -0,0 +1,49 @@
README for Lexilla library.
The Lexilla library contains a set of lexers and folders that provides support for
programming, mark-up, and data languages for the Scintilla source code editing
component.
Lexilla is made available as both a shared library and static library.
The shared library is called liblexilla.so / liblexilla.dylib / lexilla.dll on Linux / macOS /
Windows.
The static library is called liblexilla.a when built with GCC or Clang and liblexilla.lib
when built with MSVC.
Lexilla is developed on Windows, Linux, and macOS and requires a C++17 compiler.
It may work on other Unix platforms like BSD but that is not a development focus.
MSVC 2019.4, GCC 9.0, Clang 9.0, and Apple Clang 11.0 are known to work.
MSVC is only available on Windows.
GCC and Clang work on Windows and Linux.
On macOS, only Apple Clang is available.
Lexilla requires some headers from Scintilla to build and expects a directory named
"scintilla" containing a copy of Scintilla 5+ to be a peer of the Lexilla top level
directory conventionally called "lexilla".
To use GCC, run lexilla/src/makefile:
make
To use Clang, run lexilla/test/makefile:
make CLANG=1
On macOS, CLANG is set automatically so this can just be
make
To use MSVC, run lexilla/test/lexilla.mak:
nmake -f lexilla.mak
To build a debugging version of the library, add DEBUG=1 to the command:
make DEBUG=1
The built libraries are copied into lexilla/bin.
Lexilla relies on a list of lexers from the lexilla/lexers directory. If any changes are
made to the set of lexers then source and build files can be regenerated with the
lexilla/scripts/LexillaGen.py script which requires Python 3 and is tested with 3.7+.
Unix:
python3 LexillaGen.py
Windows:
pyw LexillaGen.py

View File

@ -0,0 +1,285 @@
// SciTE - Scintilla based Text Editor
/** @file LexillaAccess.cxx
** Interface to loadable lexers.
** Maintains a list of lexer library paths and CreateLexer functions.
** If list changes then load all the lexer libraries and find the functions.
** When asked to create a lexer, call each function until one succeeds.
**/
// Copyright 2019 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#include <cstring>
#include <string>
#include <string_view>
#include <vector>
#include <set>
#if !defined(_WIN32)
#include <dlfcn.h>
#else
#include <windows.h>
#endif
#include "ILexer.h"
#include "Lexilla.h"
#include "LexillaAccess.h"
namespace {
#if defined(_WIN32)
typedef FARPROC Function;
typedef HMODULE Module;
constexpr const char *pathSeparator = "\\";
#else
typedef void *Function;
typedef void *Module;
constexpr const char *pathSeparator = "/";
#endif
/// Generic function to convert from a Function(void* or FARPROC) to a function pointer.
/// This avoids undefined and conditionally defined behaviour.
template<typename T>
T FunctionPointer(Function function) noexcept {
static_assert(sizeof(T) == sizeof(function));
T fp {};
memcpy(&fp, &function, sizeof(T));
return fp;
}
#if defined(_WIN32)
std::wstring WideStringFromUTF8(std::string_view sv) {
const int sLength = static_cast<int>(sv.length());
const int cchWide = ::MultiByteToWideChar(CP_UTF8, 0, sv.data(), sLength, nullptr, 0);
std::wstring sWide(cchWide, 0);
::MultiByteToWideChar(CP_UTF8, 0, sv.data(), sLength, sWide.data(), cchWide);
return sWide;
}
#endif
// Turn off deprecation checks as LexillaAccess deprecates its wrapper over
// the deprecated LexerNameFromID. Thus use within LexillaAccess is intentional.
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else
#pragma warning(disable: 4996)
#endif
std::string directoryLoadDefault;
std::string lastLoaded;
struct LexLibrary {
Lexilla::CreateLexerFn fnCL;
Lexilla::LexerNameFromIDFn fnLNFI;
Lexilla::GetLibraryPropertyNamesFn fnGLPN;
Lexilla::SetLibraryPropertyFn fnSLP;
std::string nameSpace;
};
std::vector<LexLibrary> libraries;
std::vector<std::string> lexers;
std::vector<std::string> libraryProperties;
Function FindSymbol(Module m, const char *symbol) noexcept {
#if defined(_WIN32)
return ::GetProcAddress(m, symbol);
#else
return dlsym(m, symbol);
#endif
}
Lexilla::CreateLexerFn pCreateLexerDefault = nullptr;
bool NameContainsDot(std::string_view path) noexcept {
for (std::string_view::const_reverse_iterator it = path.crbegin();
it != path.crend(); ++it) {
if (*it == '.')
return true;
if (*it == '/' || *it == '\\')
return false;
}
return false;
}
constexpr bool HasPrefix(std::string_view s, std::string_view prefix) noexcept {
return (s.size() >= prefix.size()) && (prefix == s.substr(0, prefix.size()));
}
}
void Lexilla::SetDefault(CreateLexerFn pCreate) noexcept {
pCreateLexerDefault = pCreate;
}
void Lexilla::SetDefaultDirectory(std::string_view directory) {
directoryLoadDefault = directory;
}
bool Lexilla::Load(std::string_view sharedLibraryPaths) {
if (sharedLibraryPaths == lastLoaded) {
return !libraries.empty();
}
std::string_view paths = sharedLibraryPaths;
lexers.clear();
libraries.clear();
while (!paths.empty()) {
const size_t separator = paths.find_first_of(';');
std::string path(paths.substr(0, separator));
if (separator == std::string::npos) {
paths.remove_prefix(paths.size());
} else {
paths.remove_prefix(separator + 1);
}
if (path == ".") {
if (directoryLoadDefault.empty()) {
path = "";
} else {
path = directoryLoadDefault;
path += pathSeparator;
}
path += LEXILLA_LIB;
}
if (!NameContainsDot(path)) {
// No '.' in name so add extension
path.append(LEXILLA_EXTENSION);
}
#if defined(_WIN32)
// Convert from UTF-8 to wide characters
std::wstring wsPath = WideStringFromUTF8(path);
Module lexillaDL = ::LoadLibraryW(wsPath.c_str());
#else
Module lexillaDL = dlopen(path.c_str(), RTLD_LAZY);
#endif
if (lexillaDL) {
GetLexerCountFn fnLexerCount = FunctionPointer<GetLexerCountFn>(
FindSymbol(lexillaDL, LEXILLA_GETLEXERCOUNT));
GetLexerNameFn fnLexerName = FunctionPointer<GetLexerNameFn>(
FindSymbol(lexillaDL, LEXILLA_GETLEXERNAME));
if (fnLexerCount && fnLexerName) {
const int nLexers = fnLexerCount();
for (int i = 0; i < nLexers; i++) {
char name[100] = "";
fnLexerName(i, name, sizeof(name));
lexers.push_back(name);
}
}
CreateLexerFn fnCL = FunctionPointer<CreateLexerFn>(
FindSymbol(lexillaDL, LEXILLA_CREATELEXER));
LexerNameFromIDFn fnLNFI = FunctionPointer<LexerNameFromIDFn>(
FindSymbol(lexillaDL, LEXILLA_LEXERNAMEFROMID));
GetLibraryPropertyNamesFn fnGLPN = FunctionPointer<GetLibraryPropertyNamesFn>(
FindSymbol(lexillaDL, LEXILLA_GETLIBRARYPROPERTYNAMES));
SetLibraryPropertyFn fnSLP = FunctionPointer<SetLibraryPropertyFn>(
FindSymbol(lexillaDL, LEXILLA_SETLIBRARYPROPERTY));
GetNameSpaceFn fnGNS = FunctionPointer<GetNameSpaceFn>(
FindSymbol(lexillaDL, LEXILLA_GETNAMESPACE));
std::string nameSpace;
if (fnGNS) {
nameSpace = fnGNS();
nameSpace += LEXILLA_NAMESPACE_SEPARATOR;
}
LexLibrary lexLib {
fnCL,
fnLNFI,
fnGLPN,
fnSLP,
nameSpace
};
libraries.push_back(lexLib);
}
}
lastLoaded = sharedLibraryPaths;
std::set<std::string> nameSet;
for (const LexLibrary &lexLib : libraries) {
if (lexLib.fnGLPN) {
const char *cpNames = lexLib.fnGLPN();
if (cpNames) {
std::string_view names = cpNames;
while (!names.empty()) {
const size_t separator = names.find_first_of('\n');
std::string name(names.substr(0, separator));
nameSet.insert(name);
if (separator == std::string::npos) {
names.remove_prefix(names.size());
} else {
names.remove_prefix(separator + 1);
}
}
}
}
}
// Standard Lexilla does not have any properties so can't be added to set.
libraryProperties = std::vector<std::string>(nameSet.begin(), nameSet.end());
return !libraries.empty();
}
Scintilla::ILexer5 *Lexilla::MakeLexer(std::string_view languageName) {
std::string sLanguageName(languageName); // Ensure NUL-termination
// First, try to match namespace then name suffix
for (const LexLibrary &lexLib : libraries) {
if (lexLib.fnCL && !lexLib.nameSpace.empty()) {
if (HasPrefix(languageName, lexLib.nameSpace)) {
Scintilla::ILexer5 *pLexer = lexLib.fnCL(sLanguageName.substr(lexLib.nameSpace.size()).c_str());
if (pLexer) {
return pLexer;
}
}
}
}
// If no match with namespace, try to just match name
for (const LexLibrary &lexLib : libraries) {
if (lexLib.fnCL) {
Scintilla::ILexer5 *pLexer = lexLib.fnCL(sLanguageName.c_str());
if (pLexer) {
return pLexer;
}
}
}
if (pCreateLexerDefault) {
return pCreateLexerDefault(sLanguageName.c_str());
}
#if defined(LEXILLA_STATIC)
Scintilla::ILexer5 *pLexer = CreateLexer(sLanguageName.c_str());
if (pLexer) {
return pLexer;
}
#endif
return nullptr;
}
std::vector<std::string> Lexilla::Lexers() {
return lexers;
}
std::string Lexilla::NameFromID(int identifier) {
for (const LexLibrary &lexLib : libraries) {
if (lexLib.fnLNFI) {
const char *name = lexLib.fnLNFI(identifier);
if (name) {
return name;
}
}
}
return std::string();
}
std::vector<std::string> Lexilla::LibraryProperties() {
return libraryProperties;
}
void Lexilla::SetProperty(const char *key, const char *value) {
for (const LexLibrary &lexLib : libraries) {
if (lexLib.fnSLP) {
lexLib.fnSLP(key, value);
}
}
// Standard Lexilla does not have any properties so don't set.
}

View File

@ -0,0 +1,35 @@
// SciTE - Scintilla based Text Editor
/** @file LexillaAccess.h
** Interface to loadable lexers.
** This does not depend on SciTE code so can be copied out into other projects.
**/
// Copyright 2019 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#ifndef LEXILLAACCESS_H
#define LEXILLAACCESS_H
namespace Lexilla {
// Directory to load default Lexilla from, commonly the directory of the application.
void SetDefaultDirectory(std::string_view directory);
// Specify CreateLexer when statically linked so no hard dependency in LexillaAccess
// so it doesn't have to be built in two forms - static and dynamic.
void SetDefault(CreateLexerFn pCreate) noexcept;
// sharedLibraryPaths is a ';' separated list of shared libraries to load.
// On Win32 it is treated as UTF-8 and on Unix it is passed to dlopen directly.
// Return true if any shared libraries are loaded.
bool Load(std::string_view sharedLibraryPaths);
Scintilla::ILexer5 *MakeLexer(std::string_view languageName);
std::vector<std::string> Lexers();
[[deprecated]] std::string NameFromID(int identifier);
std::vector<std::string> LibraryProperties();
void SetProperty(const char *key, const char *value);
}
#endif

View File

@ -0,0 +1,9 @@
README for access directory.
LexillaAccess is a module that simplifies using multiple libraries that follow the Lexilla protocol.
It can be compiled into a Lexilla client application.
Applications with complex needs can copy the code and customise it to meet their requirements.
This module is not meant to be compiled into Lexilla.

View File

@ -0,0 +1 @@
This empty files ensures that the directory is created.

View File

@ -0,0 +1,207 @@
// File to suppress cppcheck warnings for files that will not be fixed.
// Does not suppress warnings where an additional occurrence of the warning may be of interest.
// Configured for cppcheck 2.12
// Coding style is to use assignments in constructor when there are many
// members to initialize or the initialization is complex or has comments.
useInitializationList
// These may be interesting but its not clear without examining each instance closely
// Would have to ensure that any_of/all_of has same early/late exits as current code and
// produces same result on empty collections
useStlAlgorithm
// Some non-explicit constructors are used for conversions or are private to lexers
noExplicitConstructor
// The performance cost of by-value passing is often small and using a reference decreases
// code legibility.
passedByValue
// cppcheck 2.11 can't find system headers on Win32.
missingIncludeSystem
// Passing temporary string into hidden object creator functions: they do not hold the argument
danglingTemporaryLifetime:lexilla/access/LexillaAccess.cxx
returnDanglingLifetime:lexilla/access/LexillaAccess.cxx
// cppcheck seems to believe that unique_ptr<char *[]>::get returns void* instead of char**
arithOperationsOnVoidPointer:lexilla/lexlib/WordList.cxx
// cppcheck 2.11 limits checking of complex functions unless --check-level=exhaustive but that
// only finds one false issue in LexRuby
checkLevelNormal:lexilla/lexers/LexBash.cxx
checkLevelNormal:lexilla/lexers/LexCPP.cxx
checkLevelNormal:lexilla/lexers/LexHTML.cxx
checkLevelNormal:lexilla/lexers/LexPerl.cxx
checkLevelNormal:lexilla/lexers/LexRuby.cxx
// Physically but not logically const.
constVariablePointer:lexilla/examples/CheckLexilla/CheckLexilla.c
// Suppress most lexer warnings since the lexers are maintained by others
redundantCondition:lexilla/lexers/LexA68k.cxx
constParameterReference:lexilla/lexers/LexAbaqus.cxx
constParameterReference:lexilla/lexers/LexAda.cxx
constParameterReference:lexilla/lexers/LexAsciidoc.cxx
constParameterCallback:lexilla/lexers/LexAsn1.cxx
knownConditionTrueFalse:lexilla/lexers/LexAU3.cxx
shadowVariable:lexilla/lexers/LexAU3.cxx
constParameterReference:lexilla/lexers/LexBaan.cxx
unreadVariable:lexilla/lexers/LexBaan.cxx
variableScope:lexilla/lexers/LexBaan.cxx
constParameterPointer:lexilla/lexers/LexBaan.cxx
constParameterReference:lexilla/lexers/LexBash.cxx
knownConditionTrueFalse:lexilla/lexers/LexBash.cxx
variableScope:lexilla/lexers/LexBash.cxx
constVariable:lexilla/lexers/LexBasic.cxx
constParameterReference:lexilla/lexers/LexCLW.cxx
knownConditionTrueFalse:lexilla/lexers/LexCLW.cxx
variableScope:lexilla/lexers/LexCmake.cxx
knownConditionTrueFalse:lexilla/lexers/LexCmake.cxx
constParameterReference:lexilla/lexers/LexCmake.cxx
constParameterReference:lexilla/lexers/LexCOBOL.cxx
constParameterReference:lexilla/lexers/LexCoffeeScript.cxx
constParameterPointer:lexilla/lexers/LexCoffeeScript.cxx
knownConditionTrueFalse:lexilla/lexers/LexCoffeeScript.cxx
constVariableReference:lexilla/lexers/LexConf.cxx
constParameterReference:lexilla/lexers/LexCPP.cxx
variableScope:lexilla/lexers/LexCSS.cxx
knownConditionTrueFalse:lexilla/lexers/LexDataflex.cxx
constParameterReference:lexilla/lexers/LexDataflex.cxx
variableScope:lexilla/lexers/LexDataflex.cxx
knownConditionTrueFalse:lexilla/lexers/LexECL.cxx
variableScope:lexilla/lexers/LexECL.cxx
constParameter:lexilla/lexers/LexEDIFACT.cxx
constParameterPointer:lexilla/lexers/LexEDIFACT.cxx
knownConditionTrueFalse:lexilla/lexers/LexEiffel.cxx
variableScope:lexilla/lexers/LexErlang.cxx
knownConditionTrueFalse:lexilla/lexers/LexEScript.cxx
constParameter:lexilla/lexers/LexFortran.cxx
constParameterReference:lexilla/lexers/LexFortran.cxx
redundantContinue:lexilla/lexers/LexFortran.cxx
knownConditionTrueFalse:lexilla/lexers/LexFSharp.cxx
constParameterReference:lexilla/lexers/LexGAP.cxx
constParameterReference:lexilla/lexers/LexGDScript.cxx
variableScope:lexilla/lexers/LexGui4Cli.cxx
constParameterReference:lexilla/lexers/LexHaskell.cxx
constParameterReference:lexilla/lexers/LexHex.cxx
knownConditionTrueFalse:lexilla/lexers/LexHex.cxx
constVariable:lexilla/lexers/LexHollywood.cxx
variableScope:lexilla/lexers/LexInno.cxx
constVariableReference:lexilla/lexers/LexInno.cxx
constParameterReference:lexilla/lexers/LexJSON.cxx
constParameterPointer:lexilla/lexers/LexJulia.cxx
constParameterReference:lexilla/lexers/LexJulia.cxx
knownConditionTrueFalse:lexilla/lexers/LexJulia.cxx
unreadVariable:lexilla/lexers/LexJulia.cxx
variableScope:lexilla/lexers/LexJulia.cxx
variableScope:lexilla/lexers/LexLaTeX.cxx
constParameterReference:lexilla/lexers/LexLaTeX.cxx
constParameterPointer:lexilla/lexers/LexMagik.cxx
constParameterReference:lexilla/lexers/LexMagik.cxx
constParameterReference:lexilla/lexers/LexMarkdown.cxx
constParameterPointer:lexilla/lexers/LexMatlab.cxx
constParameterReference:lexilla/lexers/LexMatlab.cxx
unreadVariable:lexilla/lexers/LexMatlab.cxx
variableScope:lexilla/lexers/LexMatlab.cxx
variableScope:lexilla/lexers/LexMetapost.cxx
constParameterReference:lexilla/lexers/LexModula.cxx
variableScope:lexilla/lexers/LexModula.cxx
constParameterReference:lexilla/lexers/LexMPT.cxx
variableScope:lexilla/lexers/LexMSSQL.cxx
shadowArgument:lexilla/lexers/LexMySQL.cxx
constParameterReference:lexilla/lexers/LexNim.cxx
constParameterReference:lexilla/lexers/LexNimrod.cxx
knownConditionTrueFalse:lexilla/lexers/LexNimrod.cxx
variableScope:lexilla/lexers/LexNimrod.cxx
variableScope:lexilla/lexers/LexNsis.cxx
constParameterReference:lexilla/lexers/LexNsis.cxx
knownConditionTrueFalse:lexilla/lexers/LexNsis.cxx
variableScope:lexilla/lexers/LexOpal.cxx
constParameterReference:lexilla/lexers/LexOpal.cxx
knownConditionTrueFalse:lexilla/lexers/LexOpal.cxx
constParameterReference:lexilla/lexers/LexOScript.cxx
constParameterReference:lexilla/lexers/LexPascal.cxx
variableScope:lexilla/lexers/LexPB.cxx
constParameterReference:lexilla/lexers/LexPerl.cxx
constVariableReference:lexilla/lexers/LexPerl.cxx
knownConditionTrueFalse:lexilla/lexers/LexPerl.cxx
constParameterReference:lexilla/lexers/LexPLM.cxx
constParameterReference:lexilla/lexers/LexPO.cxx
constParameterReference:lexilla/lexers/LexPython.cxx
shadowVariable:lexilla/lexers/LexPowerPro.cxx
knownConditionTrueFalse:lexilla/lexers/LexPowerPro.cxx
variableScope:lexilla/lexers/LexProgress.cxx
constParameterReference:lexilla/lexers/LexProgress.cxx
constParameterReference:lexilla/lexers/LexRaku.cxx
variableScope:lexilla/lexers/LexRaku.cxx
redundantInitialization:lexilla/lexers/LexRegistry.cxx
constParameterReference:lexilla/lexers/LexRuby.cxx
constParameterReference:lexilla/lexers/LexRust.cxx
knownConditionTrueFalse:lexilla/lexers/LexScriptol.cxx
variableScope:lexilla/lexers/LexSpecman.cxx
unreadVariable:lexilla/lexers/LexSpice.cxx
constParameterReference:lexilla/lexers/LexSpice.cxx
constParameterReference:lexilla/lexers/LexSTTXT.cxx
constParameterReference:lexilla/lexers/LexTACL.cxx
knownConditionTrueFalse:lexilla/lexers/LexTACL.cxx
clarifyCalculation:lexilla/lexers/LexTADS3.cxx
constParameterReference:lexilla/lexers/LexTADS3.cxx
constParameterReference:lexilla/lexers/LexTAL.cxx
constVariableReference:lexilla/lexers/LexTCL.cxx
invalidscanf:lexilla/lexers/LexTCMD.cxx
constParameterReference:lexilla/lexers/LexTeX.cxx
variableScope:lexilla/lexers/LexTeX.cxx
knownConditionTrueFalse:lexilla/lexers/LexTxt2tags.cxx
knownConditionTrueFalse:lexilla/lexers/LexVB.cxx
constParameterReference:lexilla/lexers/LexVerilog.cxx
variableScope:lexilla/lexers/LexVerilog.cxx
badBitmaskCheck:lexilla/lexers/LexVerilog.cxx
uselessCallsSubstr:lexilla/lexers/LexVerilog.cxx
constParameterReference:lexilla/lexers/LexVHDL.cxx
constVariable:lexilla/lexers/LexVHDL.cxx
shadowVariable:lexilla/lexers/LexVHDL.cxx
unreadVariable:lexilla/lexers/LexVHDL.cxx
variableScope:lexilla/lexers/LexVHDL.cxx
unreadVariable:lexilla/lexers/LexVisualProlog.cxx
variableScope:lexilla/lexers/LexVisualProlog.cxx
shiftTooManyBitsSigned:lexilla/lexers/LexVisualProlog.cxx
iterateByValue:lexilla/lexers/LexVisualProlog.cxx
unreadVariable:lexilla/lexers/LexX12.cxx
constVariableReference:lexilla/lexers/LexX12.cxx
constParameterPointer:lexilla/lexers/LexX12.cxx
uselessCallsSubstr:lexilla/lexers/LexX12.cxx
constParameterReference:lexilla/lexers/LexYAML.cxx
constParameterPointer:lexilla/lexers/LexYAML.cxx
knownConditionTrueFalse:lexilla/lexers/LexYAML.cxx
// These are due to Accessor::IndentAmount not declaring the callback as taking a const.
// Changing this could cause problems for downstream projects.
constParameterCallback:lexilla/lexers/LexEiffel.cxx
constParameterCallback:lexilla/lexers/LexGDScript.cxx
constParameterCallback:lexilla/lexers/LexPython.cxx
constParameterCallback:lexilla/lexers/LexScriptol.cxx
constParameterCallback:lexilla/lexers/LexVB.cxx
constVariableReference:lexilla/lexers/LexBibTeX.cxx
constVariableReference:lexilla/lexers/LexCSS.cxx
constVariableReference:lexilla/lexers/LexCrontab.cxx
constVariableReference:lexilla/lexers/LexGui4Cli.cxx
constVariableReference:lexilla/lexers/LexMetapost.cxx
constVariableReference:lexilla/lexers/LexOpal.cxx
// Suppress everything in test example files
*:lexilla/test/examples/*
// Suppress everything in catch.hpp as won't be changing
*:lexilla/test/unit/catch.hpp
// cppcheck gives up inside catch.hpp
*:lexilla/test/unit/UnitTester.cxx
*:lexilla/test/unit/unitTest.cxx
// Tests often test things that are always true
knownConditionTrueFalse:lexilla/test/unit/testCharacterSet.cxx
// cppcheck fails REQUIRE from Catch
comparisonOfFuncReturningBoolError:lexilla/test/unit/*.cxx

View File

@ -0,0 +1 @@
@del /S /Q *.a *.aps *.bsc *.dll *.dsw *.exe *.idb *.ilc *.ild *.ilf *.ilk *.ils *.lib *.map *.ncb *.obj *.o *.opt *.ipdb *.pdb *.plg *.res *.sbr *.tds *.exp *.tlog *.lastbuildstate >NUL:

View File

@ -0,0 +1,161 @@
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org" />
<meta name="generator" content="SciTE" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" />
<meta name="Description"
content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." />
<meta name="Date.Modified" content="20240423" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
.logo {
background: url(https://www.scintilla.org/LexillaLogo.png) no-repeat;
background-image: image-set(
url(https://www.scintilla.org/LexillaLogo.png) 1x,
url(https://www.scintilla.org/LexillaLogo2x.png) 2x );
height:150px;
}
#versionlist {
margin: 0;
padding: .5em;
list-style-type: none;
color: #FFCC99;
background: #000000;
}
#versionlist li {
margin-bottom: .5em;
}
#menu {
margin: 0;
padding: .5em 0;
list-style-type: none;
font-size: larger;
background: #CCCCCC;
}
#menu li {
margin: 0;
padding: 0 .5em;
display: inline;
}
</style>
<script type="text/javascript">
function IsRemote() {
var loc = '' + window.location;
return (loc.indexOf('http:')) != -1 || (loc.indexOf('https:') != -1);
}
</script>
<title>
Lexilla
</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td width="256">
</td>
<td width="40%" align="left">
<font color="#FFCC99" size="4"> A library of language lexers for use with Scintilla</font>
</td>
<td width="40%" align="right">
<font color="#FFCC99" size="3">Release version 5.3.2<br />
Site last modified April 23 2024</font>
</td>
<td width="20%">
&nbsp;
</td>
</tr>
</table>
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td width="100%" class="logo">
&nbsp;
</td>
</tr>
</table>
<ul id="versionlist">
<li>Version 5.3.2 improves COBOL, HTML, Lua, Ruby, and Rust.</li>
<li>Version 5.3.1 improves Assembler, Bash, Batch, JavaScript, Python, and Ruby.</li>
<li>Version 5.3.0 improves Bash, HTML, and Lua.</li>
<li>Version 5.2.9 fixes potential problems on macOS 12 and older when built with Xcode 15.0.</li>
<li>Version 5.2.8 improves Python and R.</li>
</ul>
<ul id="menu">
<li id="remote1"><a href="https://www.scintilla.org/SciTEImage.html">Screenshot</a></li>
<li id="remote2"><a href="https://www.scintilla.org/LexillaDownload.html">Download</a></li>
<li><a href="https://www.scintilla.org/LexillaDoc.html">Documentation</a></li>
<li><a href="https://github.com/ScintillaOrg/lexilla/issues">Bugs</a></li>
<li id="remote3"><a href="https://www.scintilla.org/SciTE.html">SciTE</a></li>
<li><a href="https://www.scintilla.org/LexillaHistory.html">History</a></li>
<li><a href="https://www.scintilla.org/ScintillaRelated.html">Related</a></li>
<li id="remote4"><a href="https://www.scintilla.org/Privacy.html">Privacy</a></li>
</ul>
<script type="text/javascript" language="JavaScript"><!--
if (!IsRemote()) { //if NOT remote...
document.getElementById('remote1').style.display='none';
document.getElementById('remote2').style.display='none';
document.getElementById('remote3').style.display='none';
document.getElementById('remote4').style.display='none';
}
//--></script>
<p>
<a href="https://www.scintilla.org/LexillaDoc.html">Lexilla</a> is a free library of language
lexers that can be used with the <a href="https://www.scintilla.org/index.html">Scintilla</a>
editing component.
It comes with complete source code and a <a href="https://www.scintilla.org/License.txt">license</a> that
permits use in any free project or commercial product.
</p>
<p>
Originally, this functionality was incorporated inside Scintilla.
It has been extracted as a separate project to make it easier for contributors to work on
support for new languages and to fix bugs in existing lexers.
It also defines a protocol where projects can implement their own lexers and distribute
them as they wish.
</p>
<p>
Current development requires a recent C++ compiler that supports C++17.
The testing framework uses some C++20 features but the basic library only uses C++17.
</p>
<p>
Lexilla is currently available for Intel Win32, macOS, and Linux compatible operating
systems. It has been run on Windows 10, macOS 10.13+, and on Ubuntu 20.04 but is likely
to run on earlier systems as it has no GUI functionality.
</p>
<p>
You can <a href="https://www.scintilla.org/LexillaDownload.html">download Lexilla.</a>
</p>
<p>
The source code can be downloaded via Git at GitHub
<a href="https://github.com/ScintillaOrg/lexilla">Lexilla project page</a>.<br />
git clone https://github.com/ScintillaOrg/lexilla
</p>
<p>Current repository status:<br />
<a href="https://github.com/ScintillaOrg/lexilla/actions/workflows/build-check.yml"><img src="https://github.com/ScintillaOrg/lexilla/actions/workflows/build-check.yml/badge.svg" /></a><br />
<a href="https://github.com/ScintillaOrg/lexilla/actions/workflows/build-check-win32.yml"><img src="https://github.com/ScintillaOrg/lexilla/actions/workflows/build-check-win32.yml/badge.svg" /></a><br />
<a href="https://github.com/ScintillaOrg/lexilla/actions/workflows/build-check-macos.yml"><img src="https://github.com/ScintillaOrg/lexilla/actions/workflows/build-check-macos.yml/badge.svg" /></a>
</p>
<p>
<a href="https://www.scintilla.org/ScintillaRelated.html">Related sites.</a>
</p>
<p>
<a href="https://github.com/ScintillaOrg/lexilla/issues">Bugs and other issues.</a>
</p>
<p>
<a href="https://www.scintilla.org/LexillaHistory.html">History and contribution credits.</a>
</p>
<p>
Questions and comments about Lexilla should be directed to the
<a href="https://groups.google.com/forum/#!forum/scintilla-interest">scintilla-interest</a>
mailing list,
which is for discussion of Scintilla and related projects, their bugs and future features.
This is a low traffic list, averaging less than 20 messages per week.
To avoid spam, only list members can write to the list.
New versions of Lexilla are announced on scintilla-interest.
<br />
</p>
</body>
</html>

View File

@ -0,0 +1,254 @@
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="generator"
content="HTML Tidy for Windows (vers 1st August 2002), see www.w3.org" />
<meta name="generator" content="SciTE" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Lexilla Documentation</title>
<style type="text/css">
<!--
/*<![CDATA[*/
CODE { font-weight: bold; font-family: Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace; }
A:visited { color: blue; }
A:hover { text-decoration: underline ! important; }
A.message { text-decoration: none; font-weight: bold; font-family: Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace; }
A.seealso { text-decoration: none; font-weight: bold; font-family: Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace; }
A.toc { text-decoration: none; }
A.jump { text-decoration: none; }
LI.message { text-decoration: none; font-weight: bold; font-family: Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace; }
H2 { background: #E0EAFF; }
table {
border: 0px;
border-collapse: collapse;
}
div.console {
font-family: Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;
color: #008000;
font-weight: bold;
background: #F7FCF7;
border: 1px solid #C0D7C0;
margin: 0.3em 3em;
padding: 0.3em 0.6em;
}
span.console {
font-family: Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;
color: #008000;
font-weight: bold;
background: #F7FCF7;
border: 1px solid #C0D7C0;
margin: 0.1em 0em;
padding: 0.1em 0.3em;
}
.name {
color: #B08000;
}
/*]]>*/
-->
</style>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0"
summary="Banner">
<tr>
<td><img src="SciTEIco.png" border="3" height="64" width="64" alt="Lexilla icon" /></td>
<td><a href="index.html"
style="color:white;text-decoration:none;font-size:200%">Lexilla</a></td>
</tr>
</table>
<h1>Lexilla Documentation</h1>
<p>Last edited 21 April 2021 NH</p>
<h2>Introduction</h2>
<p>Lexilla is a library containing lexers for use with Scintilla. It can be either a static library
that is linked into an application or a shared library that is loaded at runtime.</p>
<p>Lexilla does not interact with the display so there is no need to compile it for a
particular GUI toolkit. Therefore there can be a common library shared by applications using
different GUI toolkits. In some circumstances there may need to be both 32-bit and 64-bit versions
on one system to match different applications.</p>
<p>Different extensions are commonly used for shared libraries: .so on Linux, .dylib on macOS, and .DLL on Windows.
</p>
<h2>The Lexilla protocol</h2>
<p>A set of functions is defined by Lexilla for use by applications. Libraries that provide these functions
can be used as a replacement for Lexilla or to add new lexers beyond those provided by Lexilla.</p>
<p>The Lexilla protocol is a superset of the external lexer protocol and defines these functions that may be exported from a shared library:<br />
<code>int <span class="name">GetLexerCount</span>()</code><br />
<code>void <span class="name">GetLexerName</span>(unsigned int index, char *name, int buflength)</code><br />
<code>LexerFactoryFunction <span class="name">GetLexerFactory</span>(unsigned int index)</code><br />
<code>ILexer5 *<span class="name">CreateLexer</span>(const char *name)</code><br />
<code>const char *<span class="name">LexerNameFromID</span>(int identifier)</code><br />
<code>const char *<span class="name">GetLibraryPropertyNames</span>()</code><br />
<code>void <span class="name">SetLibraryProperty</span>(const char *key, const char *value)</code><br />
<code>const char *<span class="name">GetNameSpace</span>()</code>
</p>
<p><span class="name">ILexer5</span> is defined by Scintilla in include/ILexer.h as the interface provided by lexers which is called by Scintilla.
Many clients do not actually need to call methods on <span class="name">ILexer5</span> - they just take the return from CreateLexer and plug it
straight into Scintilla so it can be treated as a machine pointer (void *).
</p>
<p><span class="name">LexerFactoryFunction</span> is defined as a function that takes no arguments and returns an <span class="name">ILexer5</span> *:
<code>ILexer5 *(*LexerFactoryFunction)()</code> but this can be ignored by most client code.
</p>
<p>The Lexilla protocol is a superset of the earlier external lexer protocol that defined the first 3 functions
(<span class="name">GetLexerCount</span>, <span class="name">GetLexerName</span>, <span class="name">GetLexerFactory</span>)
so Lexilla can be loaded by applications that support that protocol.
<span class="name">GetLexerFactory</span> will rarely be used now as it is easier to call <span class="name">CreateLexer</span>.
</p>
<p><span class="name">CreateLexer</span> is the main call that will create a lexer for a particular language. The returned lexer can then be
set as the current lexer in Scintilla by calling
<a class="seealso" href="ScintillaDoc.html#SCI_SETILEXER">SCI_SETILEXER</a>.</p>
<p><span class="name">LexerNameFromID</span> is an optional function that returns the name for a lexer identifier.
<code>LexerNameFromID(SCLEX_CPP) &rarr; "cpp"</code>.
This is a temporary affordance to make it easier to convert applications to using Lexilla.
Applications should move to using lexer names instead of IDs.
This function is deprecated, showing warnings with some compilers, and will be removed in a future version of Lexilla.</p>
<p><span class="name">SetLibraryProperty</span> and <span class="name">GetLibraryPropertyNames</span>
are optional functions that can be
defined if a library requires initialisation before calling other methods.
For example, a lexer library that reads language definitions from XML files may require that the
directory containing these files be set before a call to CreateLexer.
<code>SetLibraryProperty("definitions.directory", "/usr/share/xeditor/language-definitions")</code>
If a library implements SetLibraryProperty then it may also provide a set of valid property names with
GetLibraryPropertyNames that can then be used by the application to define configuration file property
names or user interface elements for options dialogs.</p>
<p><span class="name">GetNameSpace</span> is an optional function that returns a namespace string
that can be used to disambiguate lexers with the same name from different providers.
If Lexilla and XMLLexers both provide a "cpp" lexer than a request for "cpp" may be satisfied by either but "xmllexers.cpp"
unambiguously refers to the "cpp" lexer from XMLLexers.</p>
<h2>Building Lexilla</h2>
<p>Before using Lexilla it must be built or downloaded.</p>
<p>Lexilla requires some headers from Scintilla to build and expects a directory named
"scintilla" containing a copy of Scintilla 5+ to be a peer of the Lexilla top level
directory conventionally called "lexilla".</p>
<div>To build Lexilla, in the lexilla/src directory, run make (for gcc or clang)</div>
<div class="console">make</div>
<div>or nmake for MSVC</div>
<div class="console">nmake -f lexilla.mak</div>
<br />
<div>After building Lexilla, its test suite can be run with make/nmake in the lexilla/test directory. For gcc or clang</div>
<div class="console">make test</div>
or for MSVC<br />
<div class="console">nmake -f testlexers.mak test</div>
<div>Each test case should show "<code>Lexing ...</code>" and errors will display a diagnostic, commonly showing
a difference between the actual and expected result:<br>
<code>C:\u\hg\lexilla\test\examples\python\x.py:1: is different</code>
</div>
<p>There are also RunTest.sh / RunTest.bat scripts in the scripts directory to build Lexilla and then build and run the tests.
These both use gcc/clang, not MSVC.</p>
<p>There are Microsoft Visual C++ and Xcode projects that can be used to build Lexilla.
For Visual C++: src/Lexilla.vcxproj. For Xcode: src/Lexilla/Lexilla.xcodeproj.
There is also test/TestLexers.vcxproj to build the tests with Visual C++.</p>
<h2>Using Lexilla</h2>
<p>Definitions for using Lexilla from C and C++ are included in lexilla/include/Lexilla.h.
For C++, scintilla/include/ILexer.h should be included before Lexilla.h as the
<code>ILexer5</code> type is used.
For C, ILexer.h should not be included as C does not understand it and from C,
<code>void*</code> is used instead of <code>ILexer5*</code>.
</p>
<p>For many applications the main Lexilla operations are loading the Lexilla library, creating a
lexer and using that lexer in Scintilla.
Applications need to define the location (or locations) they expect
to find Lexilla or libraries that support the Lexilla protocol.
They also need to define how they request particular lexers, perhaps with a mapping from
file extensions to lexer names.</p>
<h3 id="CheckLexilla">From C - CheckLexilla</h3>
<p>An example C program for accessing Lexilla is provided in lexilla/examples/CheckLexilla.
Build with <span class="console">make</span> and run with <span class="console">make check</span>.
</p>
<h3>From C++ - LexillaAccess</h3>
<p>A C++ module, LexillaAccess.cxx / LexillaAccess.h is provided in lexilla/access.
This can either be compiled into the application when it is sufficient
or the source code can be copied into the application and customized when the application has additional requirements
(such as checking code signatures).
SciTE uses LexillaAccess.</p>
<p>LexillaAccess supports loading multiple shared libraries implementing the Lexilla protocol at one time.</p>
<h3>From Qt</h3>
<p>For Qt, use either LexillaAccess from above or Qt's QLibrary class. With 'Call' defined to call Scintilla APIs.<br />
<code>
#if _WIN32<br />
&nbsp;&nbsp;&nbsp;&nbsp;typedef void *(__stdcall *CreateLexerFn)(const char *name);<br />
#else<br />
&nbsp;&nbsp;&nbsp;&nbsp;typedef void *(*CreateLexerFn)(const char *name);<br />
#endif<br />
&nbsp;&nbsp;&nbsp;&nbsp;QFunctionPointer fn = QLibrary::resolve("lexilla", "CreateLexer");<br />
&nbsp;&nbsp;&nbsp;&nbsp;void *lexCpp = ((CreateLexerFn)fn)("cpp");<br />
&nbsp;&nbsp;&nbsp;&nbsp;Call(SCI_SETILEXER, 0, (sptr_t)(void *)lexCpp);<br />
</code></p>
<p>Applications may discover the set of lexers provided by a library by first calling
<span class="name">GetLexerCount</span> to find the number of lexers implemented in the library then looping over calling
<span class="name">GetLexerName</span> with integers 0 to <code>GetLexerCount()-1</code>.</p>
<p>Applications may set properties on a library by calling <span class="name">SetLibraryProperty</span> if provided.
This may be needed for initialisation so should before calling <span class="name">GetLexerCount</span> or <span class="name">CreateLexer</span>.
A set of property names may be available from <span class="name">GetLibraryPropertyNames</span> if provided.
It returns a string pointer where the string contains a list of property names separated by '\n'.
It is up to applications to define how properties are defined and persisted in its user interface
and configuration files.</p>
<h2>Modifying or adding lexers</h2>
<p>Lexilla can be modified or a new library created that can be used to replace or augment Lexilla.</p>
<p>Lexer libraries that provide the same functions as Lexilla may provide lexers for use by Scintilla,
augmenting or replacing those provided by Lexilla.
To allow initialisation of lexer libraries, a <code>SetLibraryProperty(const char *key, const char *value)</code>
may optionally be implemented. For example, a lexer library that uses XML based lexer definitions may
be provided with a directory to search for such definitions.
Lexer libraries should ignore any properties that they do not understand.
The set of properties supported by a lexer library is specified as a '\n' separated list of property names by
an optional <code>const char *GetLibraryPropertyNames()</code> function.
</p>
<p>Lexilla and its contained lexers can be tested with the TestLexers program in lexilla/test.
Read lexilla/test/README for information on building and using TestLexers.</p>
<p>An example of a simple lexer housed in a shared library that is compatible with the
Lexilla protocol can be found in lexilla/examples/SimpleLexer. It is implemented in C++.
Build with <span class="console">make</span> and check by running <a href="#CheckLexilla">CheckLexilla</a> against it with
<span class="console">make check</span>.
</p>
</body>
</html>

View File

@ -0,0 +1,71 @@
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org" />
<meta name="generator" content="SciTE" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>
Download Lexilla
</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td>
<img src="SciTEIco.png" border="3" height="64" width="64" alt="Scintilla icon" />
</td>
<td>
<a href="index.html" style="color:white;text-decoration:none"><font size="5">Download
Lexilla</font></a>
</td>
</tr>
</table>
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
<tr>
<td>
<font size="4"> <a href="https://www.scintilla.org/lexilla532.zip">
Windows</a>&nbsp;&nbsp;
<a href="https://www.scintilla.org/lexilla532.tgz">
GTK/Linux</a>&nbsp;&nbsp;
</font>
</td>
</tr>
</table>
<h2>
Download.
</h2>
<p>
The <a href="License.txt">license</a> for using Lexilla is similar to that of Python
containing very few restrictions.
</p>
<h3>
Release 5.3.2
</h3>
<h4>
Source Code
</h4>
The source code package contains all of the source code for Lexilla but no binary
executable code and is available in
<ul>
<li><a href="https://www.scintilla.org/lexilla532.zip">zip format</a> (1.3M) commonly used on Windows</li>
<li><a href="https://www.scintilla.org/lexilla532.tgz">tgz format</a> (0.9M) commonly used on Linux and compatible operating systems</li>
</ul>
Instructions for building on both Windows and Linux are included in the readme file.
<h4>
Windows Executable Code
</h4>
There is no download available containing only the Lexilla DLL.
However, it is included in the <a href="SciTEDownload.html">SciTE
executable full download</a> as Lexilla.DLL.
<p>
<a href="SciTEDownload.html">SciTE</a> is a good demonstration of Lexilla.
</p>
<p>
Previous versions can be downloaded from the <a href="LexillaHistory.html">history
page</a>.
</p>
</body>
</html>

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,144 @@
// Lexilla lexer library use example
/** @file CheckLexilla.c
** Check that Lexilla.h works.
**/
// Copyright 2021 by Neil Hodgson <neilh@scintilla.org>
// This file is in the public domain.
// If the public domain is not possible in your location then it can also be used under the same
// license as Scintilla. https://www.scintilla.org/License.txt
/* Build and run
Win32
gcc CheckLexilla.c -I ../../include -o CheckLexilla
CheckLexilla
CheckLexilla ../SimpleLexer/SimpleLexer.dll
Win32 Visual C++
cl CheckLexilla.c -I ../../include -Fe: CheckLexilla
CheckLexilla
CheckLexilla ../SimpleLexer/SimpleLexer.dll
macOS
clang CheckLexilla.c -I ../../include -o CheckLexilla
./CheckLexilla
./CheckLexilla ../SimpleLexer/SimpleLexer.dylib
Linux
gcc CheckLexilla.c -I ../../include -ldl -o CheckLexilla
./CheckLexilla
./CheckLexilla ../SimpleLexer/SimpleLexer.so
While principally meant for compilation as C to act as an example of using Lexilla
from C it can also be built as C++.
Warnings are intentionally shown for the deprecated typedef LexerNameFromIDFn when compiled with
GCC or Clang or as C++.
*/
#include <stdio.h>
#if defined(_WIN32)
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#if defined(__cplusplus)
#include "ILexer.h"
#endif
#include "Lexilla.h"
#if defined(__cplusplus)
using namespace Lexilla;
#endif
#if defined(_WIN32)
typedef FARPROC Function;
typedef HMODULE Module;
#else
typedef void *Function;
typedef void *Module;
#endif
static Function FindSymbol(Module m, const char *symbol) {
#if defined(_WIN32)
return GetProcAddress(m, symbol);
#else
return dlsym(m, symbol);
#endif
}
int main(int argc, char *argv[]) {
char szLexillaPath[] = "../../bin/" LEXILLA_LIB LEXILLA_EXTENSION;
const char *libPath = szLexillaPath;
if (argc > 1) {
libPath = argv[1];
}
#if defined(_WIN32)
Module lexillaLibrary = LoadLibraryA(libPath);
#else
Module lexillaLibrary = dlopen(libPath, RTLD_LAZY);
#endif
printf("Opened %s -> %p.\n", libPath, lexillaLibrary);
if (lexillaLibrary) {
GetLexerCountFn lexerCount = (GetLexerCountFn)FindSymbol(lexillaLibrary, LEXILLA_GETLEXERCOUNT);
if (lexerCount) {
int nLexers = lexerCount();
printf("There are %d lexers.\n", nLexers);
GetLexerNameFn lexerName = (GetLexerNameFn)FindSymbol(lexillaLibrary, LEXILLA_GETLEXERNAME);
for (int i = 0; i < nLexers; i++) {
char name[100] = "";
lexerName(i, name, sizeof(name));
printf("%s ", name);
}
printf("\n");
GetLexerFactoryFn lexerFactory = (GetLexerFactoryFn)FindSymbol(lexillaLibrary, LEXILLA_GETLEXERFACTORY);
LexerFactoryFunction lexerFactory4 = lexerFactory(4); // 4th entry is "as" which is an object lexer so works
printf("Lexer factory 4 -> %p.\n", lexerFactory4);
CreateLexerFn lexerCreate = (CreateLexerFn)FindSymbol(lexillaLibrary, LEXILLA_CREATELEXER);
ILexer5 *lexerCpp = lexerCreate("cpp");
printf("Created cpp lexer -> %p.\n", lexerCpp);
LexerNameFromIDFn lexerNameFromID = (LexerNameFromIDFn)FindSymbol(lexillaLibrary, LEXILLA_LEXERNAMEFROMID);
if (lexerNameFromID) {
const char *lexerNameCpp = lexerNameFromID(3); // SCLEX_CPP=3
if (lexerNameCpp) {
printf("Lexer name 3 -> %s.\n", lexerNameCpp);
} else {
printf("Lexer name 3 not available.\n");
}
} else {
printf("Lexer name from ID not supported.\n");
}
GetLibraryPropertyNamesFn libraryProperties = (GetLibraryPropertyNamesFn)FindSymbol(lexillaLibrary, LEXILLA_GETLIBRARYPROPERTYNAMES);
if (libraryProperties) {
const char *names = libraryProperties();
printf("Property names '%s'.\n", names);
} else {
printf("Property names not supported.\n");
}
SetLibraryPropertyFn librarySetProperty = (SetLibraryPropertyFn)FindSymbol(lexillaLibrary, LEXILLA_SETLIBRARYPROPERTY);
if (librarySetProperty) {
librarySetProperty("key", "value");
} else {
printf("Set property not supported.\n");
}
GetNameSpaceFn libraryNameSpace = (GetLibraryPropertyNamesFn)FindSymbol(lexillaLibrary, LEXILLA_GETNAMESPACE);
if (libraryNameSpace) {
const char *nameSpace = libraryNameSpace();
printf("Name space '%s'.\n", nameSpace);
} else {
printf("Name space not supported.\n");
}
}
}
}

View File

@ -0,0 +1,22 @@
.PHONY: all check clean
INCLUDES = -I ../../include
EXE = $(if $(windir),CheckLexilla.exe,CheckLexilla)
ifdef windir
RM = $(if $(wildcard $(dir $(SHELL))rm.exe), $(dir $(SHELL))rm.exe -f, del /q)
CC = gcc
else
LIBS += -ldl
endif
all: $(EXE)
check: $(EXE)
./$(EXE)
clean:
$(RM) $(EXE)
$(EXE): *.c
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $^ $(LIBS) $(LDLIBS) -o $@

View File

@ -0,0 +1,123 @@
// A simple lexer
/** @file SimpleLexer.cxx
** A lexer that follows the Lexilla protocol to allow it to be used from Lexilla clients like SciTE.
** The lexer applies alternating styles (0,1) to bytes of the text.
**/
// Copyright 2021 by Neil Hodgson <neilh@scintilla.org>
// This file is in the public domain.
// If the public domain is not possible in your location then it can also be used under the same
// license as Scintilla. https://www.scintilla.org/License.txt
// Windows/MSVC
// cl -std:c++17 -EHsc -LD -I ../../../scintilla/include -I ../../include -I ../../lexlib SimpleLexer.cxx ../../lexlib/*.cxx
// macOS/clang
// clang++ -dynamiclib --std=c++17 -I ../../../scintilla/include -I ../../include -I ../../lexlib SimpleLexer.cxx ../../lexlib/*.cxx -o SimpleLexer.dylib
// Linux/g++
// g++ -fPIC -shared --std=c++17 -I ../../../scintilla/include -I ../../include -I ../../lexlib SimpleLexer.cxx ../../lexlib/*.cxx -o SimpleLexer.so
/* It can be demonstrated in SciTE like this, substituting the actual shared library location as lexilla.path:
lexilla.path=.;C:\u\hg\lexilla\examples\SimpleLexer\SimpleLexer.dll
lexer.*.xx=simple
style.simple.1=fore:#FF0000
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <string_view>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
// Lexilla.h should not be included here as it declares statically linked functions without the __declspec( dllexport )
#include "WordList.h"
#include "PropSetSimple.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "LexerBase.h"
using namespace Scintilla;
using namespace Lexilla;
class LexerSimple : public LexerBase {
public:
LexerSimple() {
}
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override {
try {
Accessor astyler(pAccess, &props);
if (length > 0) {
astyler.StartAt(startPos);
astyler.StartSegment(startPos);
for (unsigned int k=0; k<length; k++) {
astyler.ColourTo(startPos+k, (startPos+k)%2);
}
}
astyler.Flush();
} catch (...) {
// Should not throw into caller as may be compiled with different compiler or options
pAccess->SetErrorStatus(SC_STATUS_FAILURE);
}
}
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override {
}
static ILexer5 *LexerFactorySimple() {
try {
return new LexerSimple();
} catch (...) {
// Should not throw into caller as may be compiled with different compiler or options
return nullptr;
}
}
};
#if defined(_WIN32)
#define EXPORT_FUNCTION __declspec(dllexport)
#define CALLING_CONVENTION __stdcall
#else
#define EXPORT_FUNCTION __attribute__((visibility("default")))
#define CALLING_CONVENTION
#endif
static const char *lexerName = "simple";
extern "C" {
EXPORT_FUNCTION int CALLING_CONVENTION GetLexerCount() {
return 1;
}
EXPORT_FUNCTION void CALLING_CONVENTION GetLexerName(unsigned int index, char *name, int buflength) {
*name = 0;
if ((index == 0) && (buflength > static_cast<int>(strlen(lexerName)))) {
strcpy(name, lexerName);
}
}
EXPORT_FUNCTION LexerFactoryFunction CALLING_CONVENTION GetLexerFactory(unsigned int index) {
if (index == 0)
return LexerSimple::LexerFactorySimple;
else
return 0;
}
EXPORT_FUNCTION Scintilla::ILexer5* CALLING_CONVENTION CreateLexer(const char *name) {
if (0 == strcmp(name, lexerName)) {
return LexerSimple::LexerFactorySimple();
}
return nullptr;
}
EXPORT_FUNCTION const char * CALLING_CONVENTION GetNameSpace() {
return "example";
}
}

View File

@ -0,0 +1,38 @@
.PHONY: all check clean
INCLUDES = -I ../../../scintilla/include -I ../../include -I ../../lexlib
BASE_FLAGS += --std=c++17 -shared
ifdef windir
SHAREDEXTENSION = dll
else
ifeq ($(shell uname),Darwin)
SHAREDEXTENSION = dylib
BASE_FLAGS += -dynamiclib -arch arm64 -arch x86_64
else
BASE_FLAGS += -fPIC
SHAREDEXTENSION = so
endif
BASE_FLAGS += -fvisibility=hidden
endif
ifdef windir
RM = $(if $(wildcard $(dir $(SHELL))rm.exe), $(dir $(SHELL))rm.exe -f, del /q)
CXX = g++
endif
LIBRARY = SimpleLexer.$(SHAREDEXTENSION)
LEXLIB = ../../lexlib/*.cxx
all: $(LIBRARY)
# make check requires CheckLexilla to have already been built
check: $(LIBRARY)
../CheckLexilla/CheckLexilla ./$(LIBRARY)
clean:
$(RM) *.o *obj *.lib *.exp $(LIBRARY)
$(LIBRARY): *.cxx
$(CXX) $(INCLUDES) $(BASE_FLAGS) $(CPPFLAGS) $(CXXFLAGS) $^ $(LEXLIB) $(LIBS) $(LDLIBS) -o $@

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,108 @@
// Lexilla lexer library
/** @file Lexilla.h
** Lexilla definitions for dynamic and static linking.
** For C++, more features and type safety are available with the LexillaAccess module.
**/
// Copyright 2020 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#ifndef LEXILLA_H
#define LEXILLA_H
// Define the default Lexilla shared library name for each platform
#if defined(_WIN32)
#define LEXILLA_LIB "lexilla"
#define LEXILLA_EXTENSION ".dll"
#else
#define LEXILLA_LIB "liblexilla"
#if defined(__APPLE__)
#define LEXILLA_EXTENSION ".dylib"
#else
#define LEXILLA_EXTENSION ".so"
#endif
#endif
// On Win32 use the stdcall calling convention otherwise use the standard calling convention
#if defined(_WIN32)
#define LEXILLA_CALL __stdcall
#else
#define LEXILLA_CALL
#endif
#if defined(__OBJC2__)
// Objective C(++) treats '[' as a message expression.
#define DEPRECATE_DEFINITION
#elif defined(__cplusplus)
#define DEPRECATE_DEFINITION [[deprecated]]
#elif defined(__GNUC__) || defined(__clang__)
#define DEPRECATE_DEFINITION __attribute__((deprecated))
#else
// MSVC __declspec(deprecated) has different positioning rules to GCC so define to nothing
#define DEPRECATE_DEFINITION
#endif
#if defined(__cplusplus)
// Must have already included ILexer.h to have Scintilla::ILexer5 defined.
using Scintilla::ILexer5;
#else
typedef void ILexer5;
#endif
typedef ILexer5 *(*LexerFactoryFunction)(void);
#if defined(__cplusplus)
namespace Lexilla {
#endif
typedef int (LEXILLA_CALL *GetLexerCountFn)(void);
typedef void (LEXILLA_CALL *GetLexerNameFn)(unsigned int Index, char *name, int buflength);
typedef LexerFactoryFunction(LEXILLA_CALL *GetLexerFactoryFn)(unsigned int Index);
typedef ILexer5*(LEXILLA_CALL *CreateLexerFn)(const char *name);
DEPRECATE_DEFINITION typedef const char *(LEXILLA_CALL *LexerNameFromIDFn)(int identifier);
typedef const char *(LEXILLA_CALL *GetLibraryPropertyNamesFn)(void);
typedef void(LEXILLA_CALL *SetLibraryPropertyFn)(const char *key, const char *value);
typedef const char *(LEXILLA_CALL *GetNameSpaceFn)(void);
#if defined(__cplusplus)
}
#endif
#define LEXILLA_NAMESPACE_SEPARATOR '.'
#define LEXILLA_GETLEXERCOUNT "GetLexerCount"
#define LEXILLA_GETLEXERNAME "GetLexerName"
#define LEXILLA_GETLEXERFACTORY "GetLexerFactory"
#define LEXILLA_CREATELEXER "CreateLexer"
#define LEXILLA_LEXERNAMEFROMID "LexerNameFromID"
#define LEXILLA_GETLIBRARYPROPERTYNAMES "GetLibraryPropertyNames"
#define LEXILLA_SETLIBRARYPROPERTY "SetLibraryProperty"
#define LEXILLA_GETNAMESPACE "GetNameSpace"
// Static linking prototypes
#if defined(__cplusplus)
extern "C" {
#endif
ILexer5 * LEXILLA_CALL CreateLexer(const char *name);
int LEXILLA_CALL GetLexerCount(void);
void LEXILLA_CALL GetLexerName(unsigned int index, char *name, int buflength);
LexerFactoryFunction LEXILLA_CALL GetLexerFactory(unsigned int index);
DEPRECATE_DEFINITION const char *LEXILLA_CALL LexerNameFromID(int identifier);
const char * LEXILLA_CALL GetLibraryPropertyNames(void);
void LEXILLA_CALL SetLibraryProperty(const char *key, const char *value);
const char *LEXILLA_CALL GetNameSpace(void);
#if defined(__cplusplus)
}
#endif
#if defined(__cplusplus)
namespace Lexilla {
class LexerModule;
}
// Add a static lexer (in the same binary) to Lexilla's list
void AddStaticLexerModule(Lexilla::LexerModule *plm);
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,348 @@
// Scintilla source code edit control
/** @file LexA68k.cxx
** Lexer for Assembler, just for the MASM syntax
** Written by Martial Demolins AKA Folco
**/
// Copyright 2010 Martial Demolins <mdemolins(a)gmail.com>
// 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;
// Return values for GetOperatorType
#define NO_OPERATOR 0
#define OPERATOR_1CHAR 1
#define OPERATOR_2CHAR 2
/**
* IsIdentifierStart
*
* Return true if the given char is a valid identifier first char
*/
static inline bool IsIdentifierStart (const int ch)
{
return (isalpha(ch) || (ch == '_') || (ch == '\\'));
}
/**
* IsIdentifierChar
*
* Return true if the given char is a valid identifier char
*/
static inline bool IsIdentifierChar (const int ch)
{
return (isalnum(ch) || (ch == '_') || (ch == '@') || (ch == ':') || (ch == '.'));
}
/**
* GetOperatorType
*
* Return:
* NO_OPERATOR if char is not an operator
* OPERATOR_1CHAR if the operator is one char long
* OPERATOR_2CHAR if the operator is two chars long
*/
static inline int GetOperatorType (const int ch1, const int ch2)
{
int OpType = NO_OPERATOR;
if ((ch1 == '+') || (ch1 == '-') || (ch1 == '*') || (ch1 == '/') || (ch1 == '#') ||
(ch1 == '(') || (ch1 == ')') || (ch1 == '~') || (ch1 == '&') || (ch1 == '|') || (ch1 == ','))
OpType = OPERATOR_1CHAR;
else if ((ch1 == ch2) && (ch1 == '<' || ch1 == '>'))
OpType = OPERATOR_2CHAR;
return OpType;
}
/**
* IsBin
*
* Return true if the given char is 0 or 1
*/
static inline bool IsBin (const int ch)
{
return (ch == '0') || (ch == '1');
}
/**
* IsDoxygenChar
*
* Return true if the char may be part of a Doxygen keyword
*/
static inline bool IsDoxygenChar (const int ch)
{
return isalpha(ch) || (ch == '$') || (ch == '[') || (ch == ']') || (ch == '{') || (ch == '}');
}
/**
* ColouriseA68kDoc
*
* Main function, which colourises a 68k source
*/
static void ColouriseA68kDoc (Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], Accessor &styler)
{
// Used to buffer a string, to be able to compare it using built-in functions
char Buffer[100];
// Used to know the length of an operator
int OpType;
// Get references to keywords lists
WordList &cpuInstruction = *keywordlists[0];
WordList &registers = *keywordlists[1];
WordList &directive = *keywordlists[2];
WordList &extInstruction = *keywordlists[3];
WordList &alert = *keywordlists[4];
WordList &doxygenKeyword = *keywordlists[5];
// Instanciate a context for our source
StyleContext sc(startPos, length, initStyle, styler);
/************************************************************
*
* Parse the source
*
************************************************************/
for ( ; sc.More(); sc.Forward())
{
/************************************************************
*
* A style always terminates at the end of a line, even for
* comments (no multi-lines comments)
*
************************************************************/
if (sc.atLineStart) {
sc.SetState(SCE_A68K_DEFAULT);
}
/************************************************************
*
* If we are not in "default style", check if the style continues
* In this case, we just have to loop
*
************************************************************/
if (sc.state != SCE_A68K_DEFAULT)
{
if ( ((sc.state == SCE_A68K_NUMBER_DEC) && isdigit(sc.ch)) // Decimal number
|| ((sc.state == SCE_A68K_NUMBER_BIN) && IsBin(sc.ch)) // Binary number
|| ((sc.state == SCE_A68K_NUMBER_HEX) && isxdigit(sc.ch)) // Hexa number
|| ((sc.state == SCE_A68K_MACRO_ARG) && isdigit(sc.ch)) // Macro argument
|| ((sc.state == SCE_A68K_STRING1) && (sc.ch != '\'')) // String single-quoted
|| ((sc.state == SCE_A68K_STRING2) && (sc.ch != '\"')) // String double-quoted
|| ((sc.state == SCE_A68K_MACRO_DECLARATION) && IsIdentifierChar(sc.ch)) // Macro declaration (or global label, we don't know at this point)
|| ((sc.state == SCE_A68K_IDENTIFIER) && IsIdentifierChar(sc.ch)) // Identifier
|| ((sc.state == SCE_A68K_LABEL) && IsIdentifierChar(sc.ch)) // Label (local)
|| ((sc.state == SCE_A68K_COMMENT_DOXYGEN) && IsDoxygenChar(sc.ch)) // Doxygen keyword
|| ((sc.state == SCE_A68K_COMMENT_SPECIAL) && isalpha(sc.ch)) // Alert
|| ((sc.state == SCE_A68K_COMMENT) && !isalpha(sc.ch) && (sc.ch != '\\'))) // Normal comment
{
continue;
}
/************************************************************
*
* Check if current state terminates
*
************************************************************/
// Strings: include terminal ' or " in the current string by skipping it
if ((sc.state == SCE_A68K_STRING1) || (sc.state == SCE_A68K_STRING2)) {
sc.Forward();
}
// If a macro declaration was terminated with ':', it was a label
else if ((sc.state == SCE_A68K_MACRO_DECLARATION) && (sc.chPrev == ':')) {
sc.ChangeState(SCE_A68K_LABEL);
}
// If it wasn't a Doxygen keyword, change it to normal comment
else if (sc.state == SCE_A68K_COMMENT_DOXYGEN) {
sc.GetCurrent(Buffer, sizeof(Buffer));
if (!doxygenKeyword.InList(Buffer)) {
sc.ChangeState(SCE_A68K_COMMENT);
}
sc.SetState(SCE_A68K_COMMENT);
continue;
}
// If it wasn't an Alert, change it to normal comment
else if (sc.state == SCE_A68K_COMMENT_SPECIAL) {
sc.GetCurrent(Buffer, sizeof(Buffer));
if (!alert.InList(Buffer)) {
sc.ChangeState(SCE_A68K_COMMENT);
}
// Reset style to normal comment, or to Doxygen keyword if it begins with '\'
if (sc.ch == '\\') {
sc.SetState(SCE_A68K_COMMENT_DOXYGEN);
}
else {
sc.SetState(SCE_A68K_COMMENT);
}
continue;
}
// If we are in a comment, it's a Doxygen keyword or an Alert
else if (sc.state == SCE_A68K_COMMENT) {
if (sc.ch == '\\') {
sc.SetState(SCE_A68K_COMMENT_DOXYGEN);
}
else {
sc.SetState(SCE_A68K_COMMENT_SPECIAL);
}
continue;
}
// Check if we are at the end of an identifier
// In this case, colourise it if was a keyword.
else if ((sc.state == SCE_A68K_IDENTIFIER) && !IsIdentifierChar(sc.ch)) {
sc.GetCurrentLowered(Buffer, sizeof(Buffer)); // Buffer the string of the current context
if (cpuInstruction.InList(Buffer)) { // And check if it belongs to a keyword list
sc.ChangeState(SCE_A68K_CPUINSTRUCTION);
}
else if (extInstruction.InList(Buffer)) {
sc.ChangeState(SCE_A68K_EXTINSTRUCTION);
}
else if (registers.InList(Buffer)) {
sc.ChangeState(SCE_A68K_REGISTER);
}
else if (directive.InList(Buffer)) {
sc.ChangeState(SCE_A68K_DIRECTIVE);
}
}
// All special contexts are now handled.Come back to default style
sc.SetState(SCE_A68K_DEFAULT);
}
/************************************************************
*
* Check if we must enter a new state
*
************************************************************/
// Something which begins at the beginning of a line, and with
// - '\' + an identifier start char, or
// - '\\@' + an identifier start char
// is a local label (second case is used for macro local labels). We set it already as a label, it can't be a macro/equ declaration
if (sc.atLineStart && (sc.ch < 0x80) && IsIdentifierStart(sc.chNext) && (sc.ch == '\\')) {
sc.SetState(SCE_A68K_LABEL);
}
if (sc.atLineStart && (sc.ch < 0x80) && (sc.ch == '\\') && (sc.chNext == '\\')) {
sc.Forward(2);
if ((sc.ch == '@') && IsIdentifierStart(sc.chNext)) {
sc.ChangeState(SCE_A68K_LABEL);
sc.SetState(SCE_A68K_LABEL);
}
}
// Label and macro identifiers start at the beginning of a line
// We set both as a macro id, but if it wasn't one (':' at the end),
// it will be changed as a label.
if (sc.atLineStart && (sc.ch < 0x80) && IsIdentifierStart(sc.ch)) {
sc.SetState(SCE_A68K_MACRO_DECLARATION);
}
else if ((sc.ch < 0x80) && (sc.ch == ';')) { // Default: alert in a comment. If it doesn't match
sc.SetState(SCE_A68K_COMMENT); // with an alert, it will be toggle to a normal comment
}
else if ((sc.ch < 0x80) && isdigit(sc.ch)) { // Decimal numbers haven't prefix
sc.SetState(SCE_A68K_NUMBER_DEC);
}
else if ((sc.ch < 0x80) && (sc.ch == '%')) { // Binary numbers are prefixed with '%'
sc.SetState(SCE_A68K_NUMBER_BIN);
}
else if ((sc.ch < 0x80) && (sc.ch == '$')) { // Hexadecimal numbers are prefixed with '$'
sc.SetState(SCE_A68K_NUMBER_HEX);
}
else if ((sc.ch < 0x80) && (sc.ch == '\'')) { // String (single-quoted)
sc.SetState(SCE_A68K_STRING1);
}
else if ((sc.ch < 0x80) && (sc.ch == '\"')) { // String (double-quoted)
sc.SetState(SCE_A68K_STRING2);
}
else if ((sc.ch < 0x80) && (sc.ch == '\\') && (isdigit(sc.chNext))) { // Replacement symbols in macro are prefixed with '\'
sc.SetState(SCE_A68K_MACRO_ARG);
}
else if ((sc.ch < 0x80) && IsIdentifierStart(sc.ch)) { // An identifier: constant, label, etc...
sc.SetState(SCE_A68K_IDENTIFIER);
}
else {
if (sc.ch < 0x80) {
OpType = GetOperatorType(sc.ch, sc.chNext); // Check if current char is an operator
if (OpType != NO_OPERATOR) {
sc.SetState(SCE_A68K_OPERATOR);
if (OpType == OPERATOR_2CHAR) { // Check if the operator is 2 bytes long
sc.ForwardSetState(SCE_A68K_OPERATOR); // (>> or <<)
}
}
}
}
} // End of for()
sc.Complete();
}
// Names of the keyword lists
static const char * const a68kWordListDesc[] =
{
"CPU instructions",
"Registers",
"Directives",
"Extended instructions",
"Comment special words",
"Doxygen keywords",
0
};
LexerModule lmA68k(SCLEX_A68K, ColouriseA68kDoc, "a68k", 0, a68kWordListDesc);

View File

@ -0,0 +1,260 @@
// Scintilla source code edit control
/** @file LexAPDL.cxx
** Lexer for APDL. Based on the lexer for Assembler by The Black Horus.
** By Hadar Raz.
**/
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// 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;
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80 && (isalnum(ch) || ch == '_'));
}
static inline bool IsAnOperator(char ch) {
// '.' 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 == '%')
return true;
return false;
}
static void ColouriseAPDLDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
int stringStart = ' ';
WordList &processors = *keywordlists[0];
WordList &commands = *keywordlists[1];
WordList &slashcommands = *keywordlists[2];
WordList &starcommands = *keywordlists[3];
WordList &arguments = *keywordlists[4];
WordList &functions = *keywordlists[5];
// Do not leak onto next line
initStyle = SCE_APDL_DEFAULT;
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
// Determine if the current state should terminate.
if (sc.state == SCE_APDL_NUMBER) {
if (!(IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') ||
((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) {
sc.SetState(SCE_APDL_DEFAULT);
}
} else if (sc.state == SCE_APDL_COMMENT) {
if (sc.atLineEnd) {
sc.SetState(SCE_APDL_DEFAULT);
}
} else if (sc.state == SCE_APDL_COMMENTBLOCK) {
if (sc.atLineEnd) {
if (sc.ch == '\r') {
sc.Forward();
}
sc.ForwardSetState(SCE_APDL_DEFAULT);
}
} else if (sc.state == SCE_APDL_STRING) {
if (sc.atLineEnd) {
sc.SetState(SCE_APDL_DEFAULT);
} else if ((sc.ch == '\'' && stringStart == '\'') || (sc.ch == '\"' && stringStart == '\"')) {
sc.ForwardSetState(SCE_APDL_DEFAULT);
}
} else if (sc.state == SCE_APDL_WORD) {
if (!IsAWordChar(sc.ch)) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
if (processors.InList(s)) {
sc.ChangeState(SCE_APDL_PROCESSOR);
} else if (slashcommands.InList(s)) {
sc.ChangeState(SCE_APDL_SLASHCOMMAND);
} else if (starcommands.InList(s)) {
sc.ChangeState(SCE_APDL_STARCOMMAND);
} else if (commands.InList(s)) {
sc.ChangeState(SCE_APDL_COMMAND);
} else if (arguments.InList(s)) {
sc.ChangeState(SCE_APDL_ARGUMENT);
} else if (functions.InList(s)) {
sc.ChangeState(SCE_APDL_FUNCTION);
}
sc.SetState(SCE_APDL_DEFAULT);
}
} else if (sc.state == SCE_APDL_OPERATOR) {
if (!IsAnOperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_APDL_DEFAULT);
}
}
// Determine if a new state should be entered.
if (sc.state == SCE_APDL_DEFAULT) {
if (sc.ch == '!' && sc.chNext == '!') {
sc.SetState(SCE_APDL_COMMENTBLOCK);
} else if (sc.ch == '!') {
sc.SetState(SCE_APDL_COMMENT);
} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_APDL_NUMBER);
} else if (sc.ch == '\'' || sc.ch == '\"') {
sc.SetState(SCE_APDL_STRING);
stringStart = sc.ch;
} else if (IsAWordChar(sc.ch) || ((sc.ch == '*' || sc.ch == '/') && !isgraph(sc.chPrev))) {
sc.SetState(SCE_APDL_WORD);
} else if (IsAnOperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_APDL_OPERATOR);
}
}
}
sc.Complete();
}
//------------------------------------------------------------------------------
// 06-27-07 Sergio Lucato
// - Included code folding for Ansys APDL lexer
// - Copyied from LexBasic.cxx and modified for APDL
//------------------------------------------------------------------------------
/* Bits:
* 1 - whitespace
* 2 - operator
* 4 - identifier
* 8 - decimal digit
* 16 - hex digit
* 32 - bin digit
*/
static int character_classification[128] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 10, 6,
60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2,
2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4,
2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0
};
static bool IsSpace(int c) {
return c < 128 && (character_classification[c] & 1);
}
static bool IsIdentifier(int c) {
return c < 128 && (character_classification[c] & 4);
}
static int LowerCase(int c)
{
if (c >= 'A' && c <= 'Z')
return 'a' + c - 'A';
return c;
}
static int CheckAPDLFoldPoint(char const *token, int &level) {
if (!strcmp(token, "*if") ||
!strcmp(token, "*do") ||
!strcmp(token, "*dowhile") ) {
level |= SC_FOLDLEVELHEADERFLAG;
return 1;
}
if (!strcmp(token, "*endif") ||
!strcmp(token, "*enddo") ) {
return -1;
}
return 0;
}
static void FoldAPDLDoc(Sci_PositionU startPos, Sci_Position length, int,
WordList *[], Accessor &styler) {
Sci_Position line = styler.GetLine(startPos);
int level = styler.LevelAt(line);
int go = 0, done = 0;
Sci_Position endPos = startPos + length;
char word[256];
int wordlen = 0;
Sci_Position i;
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
// Scan for tokens at the start of the line (they may include
// whitespace, for tokens like "End Function"
for (i = startPos; i < endPos; i++) {
int c = styler.SafeGetCharAt(i);
if (!done && !go) {
if (wordlen) { // are we scanning a token already?
word[wordlen] = static_cast<char>(LowerCase(c));
if (!IsIdentifier(c)) { // done with token
word[wordlen] = '\0';
go = CheckAPDLFoldPoint(word, level);
if (!go) {
// Treat any whitespace as single blank, for
// things like "End Function".
if (IsSpace(c) && IsIdentifier(word[wordlen - 1])) {
word[wordlen] = ' ';
if (wordlen < 255)
wordlen++;
}
else // done with this line
done = 1;
}
} else if (wordlen < 255) {
wordlen++;
}
} else { // start scanning at first non-whitespace character
if (!IsSpace(c)) {
if (IsIdentifier(c)) {
word[0] = static_cast<char>(LowerCase(c));
wordlen = 1;
} else // done with this line
done = 1;
}
}
}
if (c == '\n') { // line end
if (!done && wordlen == 0 && foldCompact) // line was only space
level |= SC_FOLDLEVELWHITEFLAG;
if (level != styler.LevelAt(line))
styler.SetLevel(line, level);
level += go;
line++;
// reset state
wordlen = 0;
level &= ~SC_FOLDLEVELHEADERFLAG;
level &= ~SC_FOLDLEVELWHITEFLAG;
go = 0;
done = 0;
}
}
}
static const char * const apdlWordListDesc[] = {
"processors",
"commands",
"slashommands",
"starcommands",
"arguments",
"functions",
0
};
LexerModule lmAPDL(SCLEX_APDL, ColouriseAPDLDoc, "apdl", FoldAPDLDoc, apdlWordListDesc);

View File

@ -0,0 +1,275 @@
// Scintilla source code edit control
// @file LexASY.cxx
//Author: instanton (email: soft_share<at>126<dot>com)
// This lexer is for the Asymptote vector graphics language
// https://en.wikipedia.org/wiki/Asymptote_(vector_graphics_language)
// 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 <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;
static void ColouriseAsyDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler) {
WordList &keywords = *keywordlists[0];
WordList &keywords2 = *keywordlists[1];
CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true);
int visibleChars = 0;
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
if (sc.atLineStart) {
if (sc.state == SCE_ASY_STRING) {
sc.SetState(SCE_ASY_STRING);
}
visibleChars = 0;
}
if (sc.ch == '\\') {
if (sc.chNext == '\n' || sc.chNext == '\r') {
sc.Forward();
if (sc.ch == '\r' && sc.chNext == '\n') {
sc.Forward();
}
// continuationLine = true;
continue;
}
}
// Determine if the current state should terminate.
switch (sc.state) {
case SCE_ASY_OPERATOR:
sc.SetState(SCE_ASY_DEFAULT);
break;
case SCE_ASY_NUMBER:
if (!setWord.Contains(sc.ch)) {
sc.SetState(SCE_ASY_DEFAULT);
}
break;
case SCE_ASY_IDENTIFIER:
if (!setWord.Contains(sc.ch) || (sc.ch == '.')) {
char s[1000];
sc.GetCurrentLowered(s, sizeof(s));
if (keywords.InList(s)) {
sc.ChangeState(SCE_ASY_WORD);
} else if (keywords2.InList(s)) {
sc.ChangeState(SCE_ASY_WORD2);
}
sc.SetState(SCE_ASY_DEFAULT);
}
break;
case SCE_ASY_COMMENT:
if (sc.Match('*', '/')) {
sc.Forward();
sc.ForwardSetState(SCE_ASY_DEFAULT);
}
break;
case SCE_ASY_COMMENTLINE:
if (sc.atLineStart) {
sc.SetState(SCE_ASY_DEFAULT);
}
break;
case SCE_ASY_STRING:
if (sc.atLineEnd) {
sc.ChangeState(SCE_ASY_STRINGEOL);
} else if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_ASY_DEFAULT);
}
break;
case SCE_ASY_CHARACTER:
if (sc.atLineEnd) {
sc.ChangeState(SCE_ASY_STRINGEOL);
} else if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\'') {
sc.ForwardSetState(SCE_ASY_DEFAULT);
}
break;
}
// Determine if a new state should be entered.
if (sc.state == SCE_ASY_DEFAULT) {
if (setWordStart.Contains(sc.ch) || (sc.ch == '@')) {
sc.SetState(SCE_ASY_IDENTIFIER);
} else if (sc.Match('/', '*')) {
sc.SetState(SCE_ASY_COMMENT);
sc.Forward(); //
} else if (sc.Match('/', '/')) {
sc.SetState(SCE_ASY_COMMENTLINE);
} else if (sc.ch == '\"') {
sc.SetState(SCE_ASY_STRING);
} else if (sc.ch == '\'') {
sc.SetState(SCE_ASY_CHARACTER);
} else if (sc.ch == '#' && visibleChars == 0) {
do {
sc.Forward();
} while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
if (sc.atLineEnd) {
sc.SetState(SCE_ASY_DEFAULT);
}
} else if (isoperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_ASY_OPERATOR);
}
}
}
sc.Complete();
}
static bool IsAsyCommentStyle(int style) {
return style == SCE_ASY_COMMENT;
}
static inline bool isASYidentifier(int ch) {
return
((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ;
}
static int ParseASYWord(Sci_PositionU pos, Accessor &styler, char *word)
{
int length=0;
char ch=styler.SafeGetCharAt(pos);
*word=0;
while(isASYidentifier(ch) && length<100){
word[length]=ch;
length++;
ch=styler.SafeGetCharAt(pos+length);
}
word[length]=0;
return length;
}
static bool IsASYDrawingLine(Sci_Position line, Accessor &styler) {
Sci_Position pos = styler.LineStart(line);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
Sci_Position startpos = pos;
char buffer[100]="";
while (startpos<eol_pos){
char ch = styler[startpos];
ParseASYWord(startpos,styler,buffer);
bool drawcommands = strncmp(buffer,"draw",4)==0||
strncmp(buffer,"pair",4)==0||strncmp(buffer,"label",5)==0;
if (!drawcommands && ch!=' ') return false;
else if (drawcommands) return true;
startpos++;
}
return false;
}
static void FoldAsyDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *[], Accessor &styler) {
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position 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 (Sci_PositionU 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 && IsAsyCommentStyle(style)) {
if (!IsAsyCommentStyle(stylePrev) && (stylePrev != SCE_ASY_COMMENTLINEDOC)) {
levelNext++;
} else if (!IsAsyCommentStyle(styleNext) && (styleNext != SCE_ASY_COMMENTLINEDOC) && !atEOL) {
levelNext--;
}
}
if (style == SCE_ASY_OPERATOR) {
if (ch == '{') {
if (levelMinCurrent > levelNext) {
levelMinCurrent = levelNext;
}
levelNext++;
} else if (ch == '}') {
levelNext--;
}
}
if (atEOL && IsASYDrawingLine(lineCurrent, styler)){
if (lineCurrent==0 && IsASYDrawingLine(lineCurrent + 1, styler))
levelNext++;
else if (lineCurrent!=0 && !IsASYDrawingLine(lineCurrent - 1, styler)
&& IsASYDrawingLine(lineCurrent + 1, styler)
)
levelNext++;
else if (lineCurrent!=0 && IsASYDrawingLine(lineCurrent - 1, styler) &&
!IsASYDrawingLine(lineCurrent+1, styler))
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 (!IsASpace(ch))
visibleChars++;
}
}
static const char * const asyWordLists[] = {
"Primary keywords and identifiers",
"Secondary keywords and identifiers",
0,
};
LexerModule lmASY(SCLEX_ASYMPTOTE, ColouriseAsyDoc, "asy", FoldAsyDoc, asyWordLists);

View File

@ -0,0 +1,911 @@
// Scintilla source code edit control
// @file LexAU3.cxx
// Lexer for AutoIt3 https://www.autoitscript.com/site/
// by Jos van der Zande, jvdzande@yahoo.com
//
// Changes:
// March 28, 2004 - Added the standard Folding code
// April 21, 2004 - Added Preprosessor Table + Syntax Highlighting
// Fixed Number highlighting
// Changed default isoperator to IsAOperator to have a better match to AutoIt3
// Fixed "#comments_start" -> "#comments-start"
// Fixed "#comments_end" -> "#comments-end"
// Fixed Sendkeys in Strings when not terminated with }
// Added support for Sendkey strings that have second parameter e.g. {UP 5} or {a down}
// April 26, 2004 - Fixed # pre-processor statement inside of comment block would invalidly change the color.
// Added logic for #include <xyz.au3> to treat the <> as string
// Added underscore to IsAOperator.
// May 17, 2004 - Changed the folding logic from indent to keyword folding.
// Added Folding logic for blocks of single-commentlines or commentblock.
// triggered by: fold.comment=1
// Added Folding logic for preprocessor blocks triggered by fold.preprocessor=1
// Added Special for #region - #endregion syntax highlight and folding.
// May 30, 2004 - Fixed issue with continuation lines on If statements.
// June 5, 2004 - Added comma to Operators for better readability.
// Added fold.compact support set with fold.compact=1
// Changed folding inside of #cs-#ce. Default is no keyword folding inside comment blocks when fold.comment=1
// it will now only happen when fold.comment=2.
// Sep 5, 2004 - Added logic to handle colourizing words on the last line.
// Typed Characters now show as "default" till they match any table.
// Oct 10, 2004 - Added logic to show Comments in "Special" directives.
// Nov 1, 2004 - Added better testing for Numbers supporting x and e notation.
// Nov 28, 2004 - Added logic to handle continuation lines for syntax highlighting.
// Jan 10, 2005 - Added Abbreviations Keyword used for expansion
// Mar 24, 2005 - Updated Abbreviations Keywords to fix when followed by Operator.
// Apr 18, 2005 - Updated #CE/#Comment-End logic to take a linecomment ";" into account
// - Added folding support for With...EndWith
// - Added support for a DOT in variable names
// - Fixed Underscore in CommentBlock
// May 23, 2005 - Fixed the SentKey lexing in case of a missing }
// Aug 11, 2005 - Fixed possible bug with s_save length > 100.
// Aug 23, 2005 - Added Switch/endswitch support to the folding logic.
// Sep 27, 2005 - Fixed the SentKey lexing logic in case of multiple sentkeys.
// Mar 12, 2006 - Fixed issue with <> coloring as String in stead of Operator in rare occasions.
// Apr 8, 2006 - Added support for AutoIt3 Standard UDF library (SCE_AU3_UDF)
// Mar 9, 2007 - Fixed bug with + following a String getting the wrong Color.
// Jun 20, 2007 - Fixed Commentblock issue when LF's are used as EOL.
// Jul 26, 2007 - Fixed #endregion undetected bug.
//
// Copyright for Scintilla: 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
// Scintilla source code edit control
#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;
static inline bool IsTypeCharacter(const int ch)
{
return ch == '$';
}
static inline bool IsAWordChar(const int ch)
{
return (ch < 0x80) && (isalnum(ch) || ch == '_');
}
static inline bool IsAWordStart(const int ch)
{
return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '@' || ch == '#' || ch == '$' || ch == '.');
}
static inline bool IsAOperator(char ch) {
if (IsASCII(ch) && isalnum(ch))
return false;
if (ch == '+' || ch == '-' || ch == '*' || ch == '/' ||
ch == '&' || ch == '^' || ch == '=' || ch == '<' || ch == '>' ||
ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == ',' )
return true;
return false;
}
///////////////////////////////////////////////////////////////////////////////
// GetSendKey() filters the portion before and after a/multiple space(s)
// and return the first portion to be looked-up in the table
// also check if the second portion is valid... (up,down.on.off,toggle or a number)
///////////////////////////////////////////////////////////////////////////////
static int GetSendKey(const char *szLine, char *szKey)
{
int nFlag = 0;
int nStartFound = 0;
int nKeyPos = 0;
int nSpecPos= 0;
int nSpecNum= 1;
int nPos = 0;
char cTemp;
char szSpecial[100];
// split the portion of the sendkey in the part before and after the spaces
while ( ( (cTemp = szLine[nPos]) != '\0'))
{
// skip leading Ctrl/Shift/Alt state
if (cTemp == '{') {
nStartFound = 1;
}
//
if (nStartFound == 1) {
if ((cTemp == ' ') && (nFlag == 0) ) // get the stuff till first space
{
nFlag = 1;
// Add } to the end of the first bit for table lookup later.
szKey[nKeyPos++] = '}';
}
else if (cTemp == ' ')
{
// skip other spaces
}
else if (nFlag == 0)
{
// save first portion into var till space or } is hit
szKey[nKeyPos++] = cTemp;
}
else if ((nFlag == 1) && (cTemp != '}'))
{
// Save second portion into var...
szSpecial[nSpecPos++] = cTemp;
// check if Second portion is all numbers for repeat fuction
if (isdigit(cTemp) == false) {nSpecNum = 0;}
}
}
nPos++; // skip to next char
} // End While
// Check if the second portion is either a number or one of these keywords
szKey[nKeyPos] = '\0';
szSpecial[nSpecPos] = '\0';
if (strcmp(szSpecial,"down")== 0 || strcmp(szSpecial,"up")== 0 ||
strcmp(szSpecial,"on")== 0 || strcmp(szSpecial,"off")== 0 ||
strcmp(szSpecial,"toggle")== 0 || nSpecNum == 1 )
{
nFlag = 0;
}
else
{
nFlag = 1;
}
return nFlag; // 1 is bad, 0 is good
} // GetSendKey()
//
// Routine to check the last "none comment" character on a line to see if its a continuation
//
static bool IsContinuationLine(Sci_PositionU szLine, Accessor &styler)
{
Sci_Position nsPos = styler.LineStart(szLine);
Sci_Position nePos = styler.LineStart(szLine+1) - 2;
//int stylech = styler.StyleAt(nsPos);
while (nsPos < nePos)
{
//stylech = styler.StyleAt(nePos);
int stylech = styler.StyleAt(nsPos);
if (!(stylech == SCE_AU3_COMMENT)) {
char ch = styler.SafeGetCharAt(nePos);
if (!isspacechar(ch)) {
if (ch == '_')
return true;
else
return false;
}
}
nePos--; // skip to next char
} // End While
return false;
} // IsContinuationLine()
//
// syntax highlighting logic
static void ColouriseAU3Doc(Sci_PositionU startPos,
Sci_Position 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];
// find the first previous line without continuation character at the end
Sci_Position lineCurrent = styler.GetLine(startPos);
Sci_Position s_startPos = startPos;
// When not inside a Block comment: find First line without _
if (!(initStyle==SCE_AU3_COMMENTBLOCK)) {
while ((lineCurrent > 0 && IsContinuationLine(lineCurrent,styler)) ||
(lineCurrent > 1 && IsContinuationLine(lineCurrent-1,styler))) {
lineCurrent--;
startPos = styler.LineStart(lineCurrent); // get start position
initStyle = 0; // reset the start style to 0
}
}
// Set the new length to include it from the start and set the start position
length = length + s_startPos - startPos; // correct the total length to process
styler.StartAt(startPos);
StyleContext sc(startPos, length, initStyle, styler);
char si; // string indicator "=1 '=2
char ni; // Numeric indicator error=9 normal=0 normal+dec=1 hex=2 Enot=3
char ci; // comment indicator 0=not linecomment(;)
char s_save[100] = "";
si=0;
ni=0;
ci=0;
//$$$
for (; sc.More(); sc.Forward()) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
// **********************************************
// save the total current word for eof processing
if (IsAWordChar(sc.ch) || sc.ch == '}')
{
strcpy(s_save,s);
int tp = static_cast<int>(strlen(s_save));
if (tp < 99) {
s_save[tp] = static_cast<char>(tolower(sc.ch));
s_save[tp+1] = '\0';
}
}
// **********************************************
//
switch (sc.state)
{
case SCE_AU3_COMMENTBLOCK:
{
//Reset at line end
if (sc.atLineEnd) {
ci=0;
if (strcmp(s, "#ce")== 0 || strcmp(s, "#comments-end")== 0) {
if (sc.atLineEnd)
sc.SetState(SCE_AU3_DEFAULT);
else
sc.SetState(SCE_AU3_COMMENTBLOCK);
}
break;
}
//skip rest of line when a ; is encountered
if (sc.chPrev == ';') {
ci=2;
sc.SetState(SCE_AU3_COMMENTBLOCK);
}
// skip rest of the line
if (ci==2)
break;
// check when first character is detected on the line
if (ci==0) {
if (IsAWordStart(static_cast<char>(sc.ch)) || IsAOperator(static_cast<char>(sc.ch))) {
ci=1;
sc.SetState(SCE_AU3_COMMENTBLOCK);
}
break;
}
if (!(IsAWordChar(sc.ch) || (sc.ch == '-' && strcmp(s, "#comments") == 0))) {
if ((strcmp(s, "#ce")== 0 || strcmp(s, "#comments-end")== 0))
sc.SetState(SCE_AU3_COMMENT); // set to comment line for the rest of the line
else
ci=2; // line doesn't begin with #CE so skip the rest of the line
}
break;
}
case SCE_AU3_COMMENT:
{
if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
break;
}
case SCE_AU3_OPERATOR:
{
// check if its a COMobject
if (sc.chPrev == '.' && IsAWordChar(sc.ch)) {
sc.SetState(SCE_AU3_COMOBJ);
}
else {
sc.SetState(SCE_AU3_DEFAULT);
}
break;
}
case SCE_AU3_SPECIAL:
{
if (sc.ch == ';') {sc.SetState(SCE_AU3_COMMENT);}
if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
break;
}
case SCE_AU3_KEYWORD:
{
if (!(IsAWordChar(sc.ch) || (sc.ch == '-' && (strcmp(s, "#comments") == 0 || strcmp(s, "#include") == 0))))
{
if (!IsTypeCharacter(sc.ch))
{
if (strcmp(s, "#cs")== 0 || strcmp(s, "#comments-start")== 0 )
{
sc.ChangeState(SCE_AU3_COMMENTBLOCK);
sc.SetState(SCE_AU3_COMMENTBLOCK);
break;
}
else if (keywords.InList(s)) {
sc.ChangeState(SCE_AU3_KEYWORD);
sc.SetState(SCE_AU3_DEFAULT);
}
else if (keywords2.InList(s)) {
sc.ChangeState(SCE_AU3_FUNCTION);
sc.SetState(SCE_AU3_DEFAULT);
}
else if (keywords3.InList(s)) {
sc.ChangeState(SCE_AU3_MACRO);
sc.SetState(SCE_AU3_DEFAULT);
}
else if (keywords5.InList(s)) {
sc.ChangeState(SCE_AU3_PREPROCESSOR);
sc.SetState(SCE_AU3_DEFAULT);
if (strcmp(s, "#include")== 0)
{
si = 3; // use to determine string start for #inlude <>
}
}
else if (keywords6.InList(s)) {
sc.ChangeState(SCE_AU3_SPECIAL);
sc.SetState(SCE_AU3_SPECIAL);
}
else if ((keywords7.InList(s)) && (!IsAOperator(static_cast<char>(sc.ch)))) {
sc.ChangeState(SCE_AU3_EXPAND);
sc.SetState(SCE_AU3_DEFAULT);
}
else if (keywords8.InList(s)) {
sc.ChangeState(SCE_AU3_UDF);
sc.SetState(SCE_AU3_DEFAULT);
}
else if (strcmp(s, "_") == 0) {
sc.ChangeState(SCE_AU3_OPERATOR);
sc.SetState(SCE_AU3_DEFAULT);
}
else if (!IsAWordChar(sc.ch)) {
sc.ChangeState(SCE_AU3_DEFAULT);
sc.SetState(SCE_AU3_DEFAULT);
}
}
}
if (sc.atLineEnd) {
sc.SetState(SCE_AU3_DEFAULT);}
break;
}
case SCE_AU3_NUMBER:
{
// Numeric indicator error=9 normal=0 normal+dec=1 hex=2 E-not=3
//
// test for Hex notation
if (strcmp(s, "0") == 0 && (sc.ch == 'x' || sc.ch == 'X') && ni == 0)
{
ni = 2;
break;
}
// test for E notation
if (IsADigit(sc.chPrev) && (sc.ch == 'e' || sc.ch == 'E') && ni <= 1)
{
ni = 3;
break;
}
// Allow Hex characters inside hex numeric strings
if ((ni == 2) &&
(sc.ch == 'a' || sc.ch == 'b' || sc.ch == 'c' || sc.ch == 'd' || sc.ch == 'e' || sc.ch == 'f' ||
sc.ch == 'A' || sc.ch == 'B' || sc.ch == 'C' || sc.ch == 'D' || sc.ch == 'E' || sc.ch == 'F' ))
{
break;
}
// test for 1 dec point only
if (sc.ch == '.')
{
if (ni==0)
{
ni=1;
}
else
{
ni=9;
}
break;
}
// end of numeric string ?
if (!(IsADigit(sc.ch)))
{
if (ni==9)
{
sc.ChangeState(SCE_AU3_DEFAULT);
}
sc.SetState(SCE_AU3_DEFAULT);
}
break;
}
case SCE_AU3_VARIABLE:
{
// Check if its a COMObject
if (sc.ch == '.' && !IsADigit(sc.chNext)) {
sc.SetState(SCE_AU3_OPERATOR);
}
else if (!IsAWordChar(sc.ch)) {
sc.SetState(SCE_AU3_DEFAULT);
}
break;
}
case SCE_AU3_COMOBJ:
{
if (!(IsAWordChar(sc.ch))) {
sc.SetState(SCE_AU3_DEFAULT);
}
break;
}
case SCE_AU3_STRING:
{
// check for " to end a double qouted string or
// check for ' to end a single qouted string
if ((si == 1 && sc.ch == '\"') || (si == 2 && sc.ch == '\'') || (si == 3 && sc.ch == '>'))
{
sc.ForwardSetState(SCE_AU3_DEFAULT);
si=0;
break;
}
if (sc.atLineEnd)
{
si=0;
// at line end and not found a continuation char then reset to default
Sci_Position lineCurrent = styler.GetLine(sc.currentPos);
if (!IsContinuationLine(lineCurrent,styler))
{
sc.SetState(SCE_AU3_DEFAULT);
break;
}
}
// find Sendkeys in a STRING
if (sc.ch == '{' || sc.ch == '+' || sc.ch == '!' || sc.ch == '^' || sc.ch == '#' ) {
sc.SetState(SCE_AU3_SENT);}
break;
}
case SCE_AU3_SENT:
{
// Send key string ended
if (sc.chPrev == '}' && sc.ch != '}')
{
// set color to SENDKEY when valid sendkey .. else set back to regular string
char sk[100];
// split {111 222} and return {111} and check if 222 is valid.
// if return code = 1 then invalid 222 so must be string
if (GetSendKey(s,sk))
{
sc.ChangeState(SCE_AU3_STRING);
}
// if single char between {?} then its ok as sendkey for a single character
else if (strlen(sk) == 3)
{
sc.ChangeState(SCE_AU3_SENT);
}
// if sendkey {111} is in table then ok as sendkey
else if (keywords4.InList(sk))
{
sc.ChangeState(SCE_AU3_SENT);
}
else
{
sc.ChangeState(SCE_AU3_STRING);
}
sc.SetState(SCE_AU3_STRING);
}
else
{
// check if the start is a valid SendKey start
Sci_Position nPos = 0;
int nState = 1;
char cTemp;
while (!(nState == 2) && ((cTemp = s[nPos]) != '\0'))
{
if (cTemp == '{' && nState == 1)
{
nState = 2;
}
if (nState == 1 && !(cTemp == '+' || cTemp == '!' || cTemp == '^' || cTemp == '#' ))
{
nState = 0;
}
nPos++;
}
//Verify characters infront of { ... if not assume regular string
if (nState == 1 && (!(sc.ch == '{' || sc.ch == '+' || sc.ch == '!' || sc.ch == '^' || sc.ch == '#' ))) {
sc.ChangeState(SCE_AU3_STRING);
sc.SetState(SCE_AU3_STRING);
}
// If invalid character found then assume its a regular string
if (nState == 0) {
sc.ChangeState(SCE_AU3_STRING);
sc.SetState(SCE_AU3_STRING);
}
}
// check if next portion is again a sendkey
if (sc.atLineEnd)
{
sc.ChangeState(SCE_AU3_STRING);
sc.SetState(SCE_AU3_DEFAULT);
si = 0; // reset string indicator
}
//* check in next characters following a sentkey are again a sent key
// Need this test incase of 2 sentkeys like {F1}{ENTER} but not detect {{}
if (sc.state == SCE_AU3_STRING && (sc.ch == '{' || sc.ch == '+' || sc.ch == '!' || sc.ch == '^' || sc.ch == '#' )) {
sc.SetState(SCE_AU3_SENT);}
// check to see if the string ended...
// Sendkey string isn't complete but the string ended....
if ((si == 1 && sc.ch == '\"') || (si == 2 && sc.ch == '\''))
{
sc.ChangeState(SCE_AU3_STRING);
sc.ForwardSetState(SCE_AU3_DEFAULT);
}
break;
}
} //switch (sc.state)
// Determine if a new state should be entered:
if (sc.state == SCE_AU3_DEFAULT)
{
if (sc.ch == ';') {sc.SetState(SCE_AU3_COMMENT);}
else if (sc.ch == '#') {sc.SetState(SCE_AU3_KEYWORD);}
else if (sc.ch == '$') {sc.SetState(SCE_AU3_VARIABLE);}
else if (sc.ch == '.' && !IsADigit(sc.chNext)) {sc.SetState(SCE_AU3_OPERATOR);}
else if (sc.ch == '@') {sc.SetState(SCE_AU3_KEYWORD);}
//else if (sc.ch == '_') {sc.SetState(SCE_AU3_KEYWORD);}
else if (sc.ch == '<' && si==3) {sc.SetState(SCE_AU3_STRING);} // string after #include
else if (sc.ch == '\"') {
sc.SetState(SCE_AU3_STRING);
si = 1; }
else if (sc.ch == '\'') {
sc.SetState(SCE_AU3_STRING);
si = 2; }
else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext)))
{
sc.SetState(SCE_AU3_NUMBER);
ni = 0;
}
else if (IsAWordStart(sc.ch)) {sc.SetState(SCE_AU3_KEYWORD);}
else if (IsAOperator(static_cast<char>(sc.ch))) {sc.SetState(SCE_AU3_OPERATOR);}
else if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
}
} //for (; sc.More(); sc.Forward())
//*************************************
// Colourize the last word correctly
//*************************************
if (sc.state == SCE_AU3_KEYWORD)
{
if (strcmp(s_save, "#cs")== 0 || strcmp(s_save, "#comments-start")== 0 )
{
sc.ChangeState(SCE_AU3_COMMENTBLOCK);
sc.SetState(SCE_AU3_COMMENTBLOCK);
}
else if (keywords.InList(s_save)) {
sc.ChangeState(SCE_AU3_KEYWORD);
sc.SetState(SCE_AU3_KEYWORD);
}
else if (keywords2.InList(s_save)) {
sc.ChangeState(SCE_AU3_FUNCTION);
sc.SetState(SCE_AU3_FUNCTION);
}
else if (keywords3.InList(s_save)) {
sc.ChangeState(SCE_AU3_MACRO);
sc.SetState(SCE_AU3_MACRO);
}
else if (keywords5.InList(s_save)) {
sc.ChangeState(SCE_AU3_PREPROCESSOR);
sc.SetState(SCE_AU3_PREPROCESSOR);
}
else if (keywords6.InList(s_save)) {
sc.ChangeState(SCE_AU3_SPECIAL);
sc.SetState(SCE_AU3_SPECIAL);
}
else if (keywords7.InList(s_save) && sc.atLineEnd) {
sc.ChangeState(SCE_AU3_EXPAND);
sc.SetState(SCE_AU3_EXPAND);
}
else if (keywords8.InList(s_save)) {
sc.ChangeState(SCE_AU3_UDF);
sc.SetState(SCE_AU3_UDF);
}
else {
sc.ChangeState(SCE_AU3_DEFAULT);
sc.SetState(SCE_AU3_DEFAULT);
}
}
if (sc.state == SCE_AU3_SENT)
{
// Send key string ended
if (sc.chPrev == '}' && sc.ch != '}')
{
// set color to SENDKEY when valid sendkey .. else set back to regular string
char sk[100];
// split {111 222} and return {111} and check if 222 is valid.
// if return code = 1 then invalid 222 so must be string
if (GetSendKey(s_save,sk))
{
sc.ChangeState(SCE_AU3_STRING);
}
// if single char between {?} then its ok as sendkey for a single character
else if (strlen(sk) == 3)
{
sc.ChangeState(SCE_AU3_SENT);
}
// if sendkey {111} is in table then ok as sendkey
else if (keywords4.InList(sk))
{
sc.ChangeState(SCE_AU3_SENT);
}
else
{
sc.ChangeState(SCE_AU3_STRING);
}
sc.SetState(SCE_AU3_STRING);
}
// check if next portion is again a sendkey
if (sc.atLineEnd)
{
sc.ChangeState(SCE_AU3_STRING);
sc.SetState(SCE_AU3_DEFAULT);
}
}
//*************************************
sc.Complete();
}
//
static bool IsStreamCommentStyle(int style) {
return style == SCE_AU3_COMMENT || style == SCE_AU3_COMMENTBLOCK;
}
//
// Routine to find first none space on the current line and return its Style
// needed for comment lines not starting on pos 1
static int GetStyleFirstWord(Sci_PositionU szLine, Accessor &styler)
{
Sci_Position nsPos = styler.LineStart(szLine);
Sci_Position nePos = styler.LineStart(szLine+1) - 1;
while (isspacechar(styler.SafeGetCharAt(nsPos)) && nsPos < nePos)
{
nsPos++; // skip to next char
} // End While
return styler.StyleAt(nsPos);
} // GetStyleFirstWord()
//
static void FoldAU3Doc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler)
{
Sci_Position endPos = startPos + length;
// get settings from the config files for folding comments and preprocessor lines
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
bool foldInComment = styler.GetPropertyInt("fold.comment") == 2;
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
bool foldpreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
// Backtrack to previous line in case need to fix its fold status
Sci_Position lineCurrent = styler.GetLine(startPos);
if (startPos > 0) {
if (lineCurrent > 0) {
lineCurrent--;
startPos = styler.LineStart(lineCurrent);
}
}
// vars for style of previous/current/next lines
int style = GetStyleFirstWord(lineCurrent,styler);
int stylePrev = 0;
// find the first previous line without continuation character at the end
while ((lineCurrent > 0 && IsContinuationLine(lineCurrent,styler)) ||
(lineCurrent > 1 && IsContinuationLine(lineCurrent-1,styler))) {
lineCurrent--;
startPos = styler.LineStart(lineCurrent);
}
if (lineCurrent > 0) {
stylePrev = GetStyleFirstWord(lineCurrent-1,styler);
}
// vars for getting first word to check for keywords
bool FirstWordStart = false;
bool FirstWordEnd = false;
char szKeyword[11]="";
int szKeywordlen = 0;
char szThen[5]="";
int szThenlen = 0;
bool ThenFoundLast = false;
// var for indentlevel
int levelCurrent = SC_FOLDLEVELBASE;
if (lineCurrent > 0)
levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
int levelNext = levelCurrent;
//
int visibleChars = 0;
char chNext = styler.SafeGetCharAt(startPos);
char chPrev = ' ';
//
for (Sci_Position i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if (IsAWordChar(ch)) {
visibleChars++;
}
// get the syle for the current character neede to check in comment
int stylech = styler.StyleAt(i);
// get first word for the line for indent check max 9 characters
if (FirstWordStart && (!(FirstWordEnd))) {
if (!IsAWordChar(ch)) {
FirstWordEnd = true;
szKeyword[szKeywordlen] = '\0';
}
else {
if (szKeywordlen < 10) {
szKeyword[szKeywordlen++] = static_cast<char>(tolower(ch));
}
}
}
// start the capture of the first word
if (!(FirstWordStart)) {
if (IsAWordChar(ch) || IsAWordStart(ch) || ch == ';') {
FirstWordStart = true;
szKeyword[szKeywordlen++] = static_cast<char>(tolower(ch));
}
}
// only process this logic when not in comment section
if (!(stylech == SCE_AU3_COMMENT)) {
if (ThenFoundLast) {
if (IsAWordChar(ch)) {
ThenFoundLast = false;
}
}
// find out if the word "then" is the last on a "if" line
if (FirstWordEnd && strcmp(szKeyword,"if") == 0) {
if (szThenlen == 4) {
szThen[0] = szThen[1];
szThen[1] = szThen[2];
szThen[2] = szThen[3];
szThen[3] = static_cast<char>(tolower(ch));
if (strcmp(szThen,"then") == 0 ) {
ThenFoundLast = true;
}
}
else {
szThen[szThenlen++] = static_cast<char>(tolower(ch));
if (szThenlen == 5) {
szThen[4] = '\0';
}
}
}
}
// End of Line found so process the information
if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) {
// **************************
// Folding logic for Keywords
// **************************
// if a keyword is found on the current line and the line doesn't end with _ (continuation)
// and we are not inside a commentblock.
if (szKeywordlen > 0 && (!(chPrev == '_')) &&
((!(IsStreamCommentStyle(style)) || foldInComment)) ) {
szKeyword[szKeywordlen] = '\0';
// only fold "if" last keyword is "then" (else its a one line if)
if (strcmp(szKeyword,"if") == 0 && ThenFoundLast) {
levelNext++;
}
// create new fold for these words
if (strcmp(szKeyword,"do") == 0 || strcmp(szKeyword,"for") == 0 ||
strcmp(szKeyword,"func") == 0 || strcmp(szKeyword,"while") == 0||
strcmp(szKeyword,"with") == 0 || strcmp(szKeyword,"#region") == 0 ) {
levelNext++;
}
// create double Fold for select&switch because Case will subtract one of the current level
if (strcmp(szKeyword,"select") == 0 || strcmp(szKeyword,"switch") == 0) {
levelNext++;
levelNext++;
}
// end the fold for these words before the current line
if (strcmp(szKeyword,"endfunc") == 0 || strcmp(szKeyword,"endif") == 0 ||
strcmp(szKeyword,"next") == 0 || strcmp(szKeyword,"until") == 0 ||
strcmp(szKeyword,"endwith") == 0 ||strcmp(szKeyword,"wend") == 0){
levelNext--;
levelCurrent--;
}
// end the fold for these words before the current line and Start new fold
if (strcmp(szKeyword,"case") == 0 || strcmp(szKeyword,"else") == 0 ||
strcmp(szKeyword,"elseif") == 0 ) {
levelCurrent--;
}
// end the double fold for this word before the current line
if (strcmp(szKeyword,"endselect") == 0 || strcmp(szKeyword,"endswitch") == 0 ) {
levelNext--;
levelNext--;
levelCurrent--;
levelCurrent--;
}
// end the fold for these words on the current line
if (strcmp(szKeyword,"#endregion") == 0 ) {
levelNext--;
}
}
// Preprocessor and Comment folding
int styleNext = GetStyleFirstWord(lineCurrent + 1,styler);
// *************************************
// Folding logic for preprocessor blocks
// *************************************
// process preprosessor line
if (foldpreprocessor && style == SCE_AU3_PREPROCESSOR) {
if (!(stylePrev == SCE_AU3_PREPROCESSOR) && (styleNext == SCE_AU3_PREPROCESSOR)) {
levelNext++;
}
// fold till the last line for normal comment lines
else if (stylePrev == SCE_AU3_PREPROCESSOR && !(styleNext == SCE_AU3_PREPROCESSOR)) {
levelNext--;
}
}
// *********************************
// Folding logic for Comment blocks
// *********************************
if (foldComment && IsStreamCommentStyle(style)) {
// Start of a comment block
if (!(stylePrev==style) && IsStreamCommentStyle(styleNext) && styleNext==style) {
levelNext++;
}
// fold till the last line for normal comment lines
else if (IsStreamCommentStyle(stylePrev)
&& !(styleNext == SCE_AU3_COMMENT)
&& stylePrev == SCE_AU3_COMMENT
&& style == SCE_AU3_COMMENT) {
levelNext--;
}
// fold till the one but last line for Blockcomment lines
else if (IsStreamCommentStyle(stylePrev)
&& !(styleNext == SCE_AU3_COMMENTBLOCK)
&& style == SCE_AU3_COMMENTBLOCK) {
levelNext--;
levelCurrent--;
}
}
int levelUse = levelCurrent;
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);
}
// reset values for the next line
lineCurrent++;
stylePrev = style;
style = styleNext;
levelCurrent = levelNext;
visibleChars = 0;
// if the last character is an Underscore then don't reset since the line continues on the next line.
if (!(chPrev == '_')) {
szKeywordlen = 0;
szThenlen = 0;
FirstWordStart = false;
FirstWordEnd = false;
ThenFoundLast = false;
}
}
// save the last processed character
if (!isspacechar(ch)) {
chPrev = ch;
visibleChars++;
}
}
}
//
static const char * const AU3WordLists[] = {
"#autoit keywords",
"#autoit functions",
"#autoit macros",
"#autoit Sent keys",
"#autoit Pre-processors",
"#autoit Special",
"#autoit Expand",
"#autoit UDF",
0
};
LexerModule lmAU3(SCLEX_AU3, ColouriseAU3Doc, "au3", FoldAU3Doc , AU3WordLists);

View File

@ -0,0 +1,232 @@
// SciTE - Scintilla based Text Editor
/** @file LexAVE.cxx
** Lexer for Avenue.
**
** Written by Alexey Yutkin <yutkin@geol.msu.ru>.
**/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// 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;
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}
static inline bool IsEnumChar(const int ch) {
return (ch < 0x80) && (isalnum(ch)|| ch == '_');
}
static inline bool IsANumberChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '.' );
}
inline bool IsAWordStart(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_');
}
inline bool isAveOperator(char ch) {
if (IsASCII(ch) && 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 == '.' )
return true;
return false;
}
static void ColouriseAveDoc(
Sci_PositionU startPos,
Sci_Position 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];
// Do not leak onto next line
if (initStyle == SCE_AVE_STRINGEOL) {
initStyle = SCE_AVE_DEFAULT;
}
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
if (sc.atLineEnd) {
// Update the line state, so it can be seen by next line
Sci_Position currentLine = styler.GetLine(sc.currentPos);
styler.SetLineState(currentLine, 0);
}
if (sc.atLineStart && (sc.state == SCE_AVE_STRING)) {
// Prevent SCE_AVE_STRINGEOL from leaking back to previous line
sc.SetState(SCE_AVE_STRING);
}
// Determine if the current state should terminate.
if (sc.state == SCE_AVE_OPERATOR) {
sc.SetState(SCE_AVE_DEFAULT);
} else if (sc.state == SCE_AVE_NUMBER) {
if (!IsANumberChar(sc.ch)) {
sc.SetState(SCE_AVE_DEFAULT);
}
} else if (sc.state == SCE_AVE_ENUM) {
if (!IsEnumChar(sc.ch)) {
sc.SetState(SCE_AVE_DEFAULT);
}
} else if (sc.state == SCE_AVE_IDENTIFIER) {
if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
char s[100];
//sc.GetCurrent(s, sizeof(s));
sc.GetCurrentLowered(s, sizeof(s));
if (keywords.InList(s)) {
sc.ChangeState(SCE_AVE_WORD);
} else if (keywords2.InList(s)) {
sc.ChangeState(SCE_AVE_WORD2);
} else if (keywords3.InList(s)) {
sc.ChangeState(SCE_AVE_WORD3);
} else if (keywords4.InList(s)) {
sc.ChangeState(SCE_AVE_WORD4);
} else if (keywords5.InList(s)) {
sc.ChangeState(SCE_AVE_WORD5);
} else if (keywords6.InList(s)) {
sc.ChangeState(SCE_AVE_WORD6);
}
sc.SetState(SCE_AVE_DEFAULT);
}
} else if (sc.state == SCE_AVE_COMMENT) {
if (sc.atLineEnd) {
sc.SetState(SCE_AVE_DEFAULT);
}
} else if (sc.state == SCE_AVE_STRING) {
if (sc.ch == '\"') {
sc.ForwardSetState(SCE_AVE_DEFAULT);
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_AVE_STRINGEOL);
sc.ForwardSetState(SCE_AVE_DEFAULT);
}
}
// Determine if a new state should be entered.
if (sc.state == SCE_AVE_DEFAULT) {
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_AVE_NUMBER);
} else if (IsAWordStart(sc.ch)) {
sc.SetState(SCE_AVE_IDENTIFIER);
} else if (sc.Match('\"')) {
sc.SetState(SCE_AVE_STRING);
} else if (sc.Match('\'')) {
sc.SetState(SCE_AVE_COMMENT);
sc.Forward();
} else if (isAveOperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_AVE_OPERATOR);
} else if (sc.Match('#')) {
sc.SetState(SCE_AVE_ENUM);
sc.Forward();
}
}
}
sc.Complete();
}
static void FoldAveDoc(Sci_PositionU startPos, Sci_Position length, int /* initStyle */, WordList *[],
Accessor &styler) {
Sci_PositionU lengthDoc = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = static_cast<char>(tolower(styler[startPos]));
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
int styleNext = styler.StyleAt(startPos);
char s[10] = "";
for (Sci_PositionU i = startPos; i < lengthDoc; i++) {
char ch = static_cast<char>(tolower(chNext));
chNext = static_cast<char>(tolower(styler.SafeGetCharAt(i + 1)));
int style = styleNext;
styleNext = styler.StyleAt(i + 1);
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
if (style == SCE_AVE_WORD) {
if (ch == 't' || ch == 'f' || ch == 'w' || ch == 'e') {
for (unsigned int j = 0; j < 6; j++) {
if (!iswordchar(styler[i + j])) {
break;
}
s[j] = static_cast<char>(tolower(styler[i + j]));
s[j + 1] = '\0';
}
if ((strcmp(s, "then") == 0) || (strcmp(s, "for") == 0) || (strcmp(s, "while") == 0)) {
levelCurrent++;
}
if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0)) {
// Normally "elseif" and "then" will be on the same line and will cancel
// each other out. // As implemented, this does not support fold.at.else.
levelCurrent--;
}
}
} else if (style == SCE_AVE_OPERATOR) {
if (ch == '{' || ch == '(') {
levelCurrent++;
} else if (ch == '}' || 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);
}
LexerModule lmAVE(SCLEX_AVE, ColouriseAveDoc, "ave", FoldAveDoc);

View File

@ -0,0 +1,294 @@
// Scintilla source code edit control
/** @file LexAVS.cxx
** Lexer for AviSynth.
**/
// Copyright 2012 by Bruno Barbieri <brunorex@gmail.com>
// Heavily based on LexPOV by Neil Hodgson
// 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;
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_');
}
static inline bool IsAWordStart(int ch) {
return isalpha(ch) || (ch != ' ' && ch != '\n' && ch != '(' && 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) || ch == '.' || ch == '-' || ch == '+');
}
static void ColouriseAvsDoc(
Sci_PositionU startPos,
Sci_Position length,
int initStyle,
WordList *keywordlists[],
Accessor &styler) {
WordList &keywords = *keywordlists[0];
WordList &filters = *keywordlists[1];
WordList &plugins = *keywordlists[2];
WordList &functions = *keywordlists[3];
WordList &clipProperties = *keywordlists[4];
WordList &userDefined = *keywordlists[5];
Sci_Position currentLine = styler.GetLine(startPos);
// Initialize the block comment nesting level, if we are inside such a comment.
int blockCommentLevel = 0;
if (initStyle == SCE_AVS_COMMENTBLOCK || initStyle == SCE_AVS_COMMENTBLOCKN) {
blockCommentLevel = styler.GetLineState(currentLine - 1);
}
// Do not leak onto next line
if (initStyle == SCE_AVS_COMMENTLINE) {
initStyle = SCE_AVS_DEFAULT;
}
StyleContext sc(startPos, length, initStyle, styler);
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);
if (sc.state == SCE_AVS_COMMENTBLOCK || sc.state == SCE_AVS_COMMENTBLOCKN) {
// Inside a block comment, we set the line state
styler.SetLineState(currentLine, blockCommentLevel);
} else {
// Reset the line state
styler.SetLineState(currentLine, 0);
}
}
// Determine if the current state should terminate.
if (sc.state == SCE_AVS_OPERATOR) {
sc.SetState(SCE_AVS_DEFAULT);
} else if (sc.state == SCE_AVS_NUMBER) {
// We stop the number definition on non-numerical non-dot non-sign char
if (!IsANumberChar(sc.ch)) {
sc.SetState(SCE_AVS_DEFAULT);
}
} else if (sc.state == SCE_AVS_IDENTIFIER) {
if (!IsAWordChar(sc.ch)) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
if (keywords.InList(s)) {
sc.ChangeState(SCE_AVS_KEYWORD);
} else if (filters.InList(s)) {
sc.ChangeState(SCE_AVS_FILTER);
} else if (plugins.InList(s)) {
sc.ChangeState(SCE_AVS_PLUGIN);
} else if (functions.InList(s)) {
sc.ChangeState(SCE_AVS_FUNCTION);
} else if (clipProperties.InList(s)) {
sc.ChangeState(SCE_AVS_CLIPPROP);
} else if (userDefined.InList(s)) {
sc.ChangeState(SCE_AVS_USERDFN);
}
sc.SetState(SCE_AVS_DEFAULT);
}
} else if (sc.state == SCE_AVS_COMMENTBLOCK) {
if (sc.Match('/', '*')) {
blockCommentLevel++;
sc.Forward();
} else if (sc.Match('*', '/') && blockCommentLevel > 0) {
blockCommentLevel--;
sc.Forward();
if (blockCommentLevel == 0) {
sc.ForwardSetState(SCE_AVS_DEFAULT);
}
}
} else if (sc.state == SCE_AVS_COMMENTBLOCKN) {
if (sc.Match('[', '*')) {
blockCommentLevel++;
sc.Forward();
} else if (sc.Match('*', ']') && blockCommentLevel > 0) {
blockCommentLevel--;
sc.Forward();
if (blockCommentLevel == 0) {
sc.ForwardSetState(SCE_AVS_DEFAULT);
}
}
} else if (sc.state == SCE_AVS_COMMENTLINE) {
if (sc.atLineEnd) {
sc.ForwardSetState(SCE_AVS_DEFAULT);
}
} else if (sc.state == SCE_AVS_STRING) {
if (sc.ch == '\"') {
sc.ForwardSetState(SCE_AVS_DEFAULT);
}
} else if (sc.state == SCE_AVS_TRIPLESTRING) {
if (sc.Match("\"\"\"")) {
sc.Forward();
sc.Forward();
sc.ForwardSetState(SCE_AVS_DEFAULT);
}
}
// Determine if a new state should be entered.
if (sc.state == SCE_AVS_DEFAULT) {
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_AVS_NUMBER);
} else if (IsADigit(sc.ch) || (sc.ch == ',' && IsADigit(sc.chNext))) {
sc.Forward();
sc.SetState(SCE_AVS_NUMBER);
} else if (sc.Match('/', '*')) {
blockCommentLevel = 1;
sc.SetState(SCE_AVS_COMMENTBLOCK);
sc.Forward(); // Eat the * so it isn't used for the end of the comment
} else if (sc.Match('[', '*')) {
blockCommentLevel = 1;
sc.SetState(SCE_AVS_COMMENTBLOCKN);
sc.Forward(); // Eat the * so it isn't used for the end of the comment
} else if (sc.ch == '#') {
sc.SetState(SCE_AVS_COMMENTLINE);
} else if (sc.ch == '\"') {
if (sc.Match("\"\"\"")) {
sc.SetState(SCE_AVS_TRIPLESTRING);
} else {
sc.SetState(SCE_AVS_STRING);
}
} else if (isoperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_AVS_OPERATOR);
} else if (IsAWordStart(sc.ch)) {
sc.SetState(SCE_AVS_IDENTIFIER);
}
}
}
// End of file: complete any pending changeState
if (sc.state == SCE_AVS_IDENTIFIER) {
if (!IsAWordChar(sc.ch)) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
if (keywords.InList(s)) {
sc.ChangeState(SCE_AVS_KEYWORD);
} else if (filters.InList(s)) {
sc.ChangeState(SCE_AVS_FILTER);
} else if (plugins.InList(s)) {
sc.ChangeState(SCE_AVS_PLUGIN);
} else if (functions.InList(s)) {
sc.ChangeState(SCE_AVS_FUNCTION);
} else if (clipProperties.InList(s)) {
sc.ChangeState(SCE_AVS_CLIPPROP);
} else if (userDefined.InList(s)) {
sc.ChangeState(SCE_AVS_USERDFN);
}
sc.SetState(SCE_AVS_DEFAULT);
}
}
sc.Complete();
}
static void FoldAvsDoc(
Sci_PositionU startPos,
Sci_Position length,
int initStyle,
WordList *[],
Accessor &styler) {
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
int style = initStyle;
for (Sci_PositionU 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 && style == SCE_AVS_COMMENTBLOCK) {
if (stylePrev != SCE_AVS_COMMENTBLOCK) {
levelCurrent++;
} else if ((styleNext != SCE_AVS_COMMENTBLOCK) && !atEOL) {
// Comments don't end at end of line and the next character may be unstyled.
levelCurrent--;
}
}
if (foldComment && style == SCE_AVS_COMMENTBLOCKN) {
if (stylePrev != SCE_AVS_COMMENTBLOCKN) {
levelCurrent++;
} else if ((styleNext != SCE_AVS_COMMENTBLOCKN) && !atEOL) {
// Comments don't end at end of line and the next character may be unstyled.
levelCurrent--;
}
}
if (style == SCE_AVS_OPERATOR) {
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 avsWordLists[] = {
"Keywords",
"Filters",
"Plugins",
"Functions",
"Clip properties",
"User defined functions",
0,
};
LexerModule lmAVS(SCLEX_AVS, ColouriseAvsDoc, "avs", FoldAvsDoc, avsWordLists);

View File

@ -0,0 +1,606 @@
// Scintilla source code edit control
/** @file LexAbaqus.cxx
** Lexer for ABAQUS. Based on the lexer for APDL by Hadar Raz.
** By Sergio Lucato.
** Sort of completely rewritten by Gertjan Kloosterman
**/
// The License.txt file describes the conditions under which this software may be distributed.
// Code folding copyied and modified from LexBasic.cxx
#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;
static inline bool IsAKeywordChar(const int ch) {
return (ch < 0x80 && (isalnum(ch) || (ch == '_') || (ch == ' ')));
}
static inline bool IsASetChar(const int ch) {
return (ch < 0x80 && (isalnum(ch) || (ch == '_') || (ch == '.') || (ch == '-')));
}
static void ColouriseABAQUSDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList*[] /* *keywordlists[] */,
Accessor &styler) {
enum localState { KW_LINE_KW, KW_LINE_COMMA, KW_LINE_PAR, KW_LINE_EQ, KW_LINE_VAL, \
DAT_LINE_VAL, DAT_LINE_COMMA,\
COMMENT_LINE,\
ST_ERROR, LINE_END } state ;
// Do not leak onto next line
state = LINE_END ;
initStyle = SCE_ABAQUS_DEFAULT;
StyleContext sc(startPos, length, initStyle, styler);
// Things are actually quite simple
// we have commentlines
// keywordlines and datalines
// On a data line there will only be colouring of numbers
// a keyword line is constructed as
// *word,[ paramname[=paramvalue]]*
// if the line ends with a , the keyword line continues onto the new line
for (; sc.More(); sc.Forward()) {
switch ( state ) {
case KW_LINE_KW :
if ( sc.atLineEnd ) {
// finished the line in keyword state, switch to LINE_END
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = LINE_END ;
} else if ( IsAKeywordChar(sc.ch) ) {
// nothing changes
state = KW_LINE_KW ;
} else if ( sc.ch == ',' ) {
// Well well we say a comma, arguments *MUST* follow
sc.SetState(SCE_ABAQUS_OPERATOR) ;
state = KW_LINE_COMMA ;
} else {
// Flag an error
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
state = ST_ERROR ;
}
// Done with processing
break ;
case KW_LINE_COMMA :
// acomma on a keywordline was seen
if ( IsAKeywordChar(sc.ch)) {
sc.SetState(SCE_ABAQUS_ARGUMENT) ;
state = KW_LINE_PAR ;
} else if ( sc.atLineEnd || (sc.ch == ',') ) {
// we remain in keyword mode
state = KW_LINE_COMMA ;
} else if ( sc.ch == ' ' ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = KW_LINE_COMMA ;
} else {
// Anything else constitutes an error
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
state = ST_ERROR ;
}
break ;
case KW_LINE_PAR :
if ( sc.atLineEnd ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = LINE_END ;
} else if ( IsAKeywordChar(sc.ch) || (sc.ch == '-') ) {
// remain in this state
state = KW_LINE_PAR ;
} else if ( sc.ch == ',' ) {
sc.SetState(SCE_ABAQUS_OPERATOR) ;
state = KW_LINE_COMMA ;
} else if ( sc.ch == '=' ) {
sc.SetState(SCE_ABAQUS_OPERATOR) ;
state = KW_LINE_EQ ;
} else {
// Anything else constitutes an error
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
state = ST_ERROR ;
}
break ;
case KW_LINE_EQ :
if ( sc.ch == ' ' ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
// remain in this state
state = KW_LINE_EQ ;
} else if ( IsADigit(sc.ch) || (sc.ch == '-') || (sc.ch == '.' && IsADigit(sc.chNext)) ) {
sc.SetState(SCE_ABAQUS_NUMBER) ;
state = KW_LINE_VAL ;
} else if ( IsAKeywordChar(sc.ch) ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = KW_LINE_VAL ;
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
sc.SetState(SCE_ABAQUS_STRING) ;
state = KW_LINE_VAL ;
} else {
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
state = ST_ERROR ;
}
break ;
case KW_LINE_VAL :
if ( sc.atLineEnd ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = LINE_END ;
} else if ( IsASetChar(sc.ch) && (sc.state == SCE_ABAQUS_DEFAULT) ) {
// nothing changes
state = KW_LINE_VAL ;
} else if (( (IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') ||
((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) &&
(sc.state == SCE_ABAQUS_NUMBER)) {
// remain in number mode
state = KW_LINE_VAL ;
} else if (sc.state == SCE_ABAQUS_STRING) {
// accept everything until a closing quote
if ( sc.ch == '\'' || sc.ch == '\"' ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = KW_LINE_VAL ;
}
} else if ( sc.ch == ',' ) {
sc.SetState(SCE_ABAQUS_OPERATOR) ;
state = KW_LINE_COMMA ;
} else {
// anything else is an error
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
state = ST_ERROR ;
}
break ;
case DAT_LINE_VAL :
if ( sc.atLineEnd ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = LINE_END ;
} else if ( IsASetChar(sc.ch) && (sc.state == SCE_ABAQUS_DEFAULT) ) {
// nothing changes
state = DAT_LINE_VAL ;
} else if (( (IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') ||
((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) &&
(sc.state == SCE_ABAQUS_NUMBER)) {
// remain in number mode
state = DAT_LINE_VAL ;
} else if (sc.state == SCE_ABAQUS_STRING) {
// accept everything until a closing quote
if ( sc.ch == '\'' || sc.ch == '\"' ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = DAT_LINE_VAL ;
}
} else if ( sc.ch == ',' ) {
sc.SetState(SCE_ABAQUS_OPERATOR) ;
state = DAT_LINE_COMMA ;
} else {
// anything else is an error
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
state = ST_ERROR ;
}
break ;
case DAT_LINE_COMMA :
// a comma on a data line was seen
if ( sc.atLineEnd ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = LINE_END ;
} else if ( sc.ch == ' ' ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = DAT_LINE_COMMA ;
} else if (sc.ch == ',') {
sc.SetState(SCE_ABAQUS_OPERATOR) ;
state = DAT_LINE_COMMA ;
} else if ( IsADigit(sc.ch) || (sc.ch == '-')|| (sc.ch == '.' && IsADigit(sc.chNext)) ) {
sc.SetState(SCE_ABAQUS_NUMBER) ;
state = DAT_LINE_VAL ;
} else if ( IsAKeywordChar(sc.ch) ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = DAT_LINE_VAL ;
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
sc.SetState(SCE_ABAQUS_STRING) ;
state = DAT_LINE_VAL ;
} else {
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
state = ST_ERROR ;
}
break ;
case COMMENT_LINE :
if ( sc.atLineEnd ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = LINE_END ;
}
break ;
case ST_ERROR :
if ( sc.atLineEnd ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = LINE_END ;
}
break ;
case LINE_END :
if ( sc.atLineEnd || sc.ch == ' ' ) {
// nothing changes
state = LINE_END ;
} else if ( sc.ch == '*' ) {
if ( sc.chNext == '*' ) {
state = COMMENT_LINE ;
sc.SetState(SCE_ABAQUS_COMMENT) ;
} else {
state = KW_LINE_KW ;
sc.SetState(SCE_ABAQUS_STARCOMMAND) ;
}
} else {
// it must be a data line, things are as if we are in DAT_LINE_COMMA
if ( sc.ch == ',' ) {
sc.SetState(SCE_ABAQUS_OPERATOR) ;
state = DAT_LINE_COMMA ;
} else if ( IsADigit(sc.ch) || (sc.ch == '-')|| (sc.ch == '.' && IsADigit(sc.chNext)) ) {
sc.SetState(SCE_ABAQUS_NUMBER) ;
state = DAT_LINE_VAL ;
} else if ( IsAKeywordChar(sc.ch) ) {
sc.SetState(SCE_ABAQUS_DEFAULT) ;
state = DAT_LINE_VAL ;
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
sc.SetState(SCE_ABAQUS_STRING) ;
state = DAT_LINE_VAL ;
} else {
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
state = ST_ERROR ;
}
}
break ;
}
}
sc.Complete();
}
//------------------------------------------------------------------------------
// This copyied and modified from LexBasic.cxx
//------------------------------------------------------------------------------
/* Bits:
* 1 - whitespace
* 2 - operator
* 4 - identifier
* 8 - decimal digit
* 16 - hex digit
* 32 - bin digit
*/
static int character_classification[128] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 10, 6,
60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2,
2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4,
2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0
};
static bool IsSpace(int c) {
return c < 128 && (character_classification[c] & 1);
}
static bool IsIdentifier(int c) {
return c < 128 && (character_classification[c] & 4);
}
static int LowerCase(int c)
{
if (c >= 'A' && c <= 'Z')
return 'a' + c - 'A';
return c;
}
static Sci_Position LineEnd(Sci_Position line, Accessor &styler)
{
const Sci_Position docLines = styler.GetLine(styler.Length() - 1); // Available last line
Sci_Position eol_pos ;
// if the line is the last line, the eol_pos is styler.Length()
// eol will contain a new line, or a virtual new line
if ( docLines == line )
eol_pos = styler.Length() ;
else
eol_pos = styler.LineStart(line + 1) - 1;
return eol_pos ;
}
static Sci_Position LineStart(Sci_Position line, Accessor &styler)
{
return styler.LineStart(line) ;
}
// LineType
//
// bits determines the line type
// 1 : data line
// 2 : only whitespace
// 3 : data line with only whitespace
// 4 : keyword line
// 5 : block open keyword line
// 6 : block close keyword line
// 7 : keyword line in error
// 8 : comment line
static int LineType(Sci_Position line, Accessor &styler) {
Sci_Position pos = LineStart(line, styler) ;
Sci_Position eol_pos = LineEnd(line, styler) ;
int c ;
char ch = ' ';
Sci_Position i = pos ;
while ( i < eol_pos ) {
c = styler.SafeGetCharAt(i);
ch = static_cast<char>(LowerCase(c));
// We can say something as soon as no whitespace
// was encountered
if ( !IsSpace(c) )
break ;
i++ ;
}
if ( i >= eol_pos ) {
// This is a whitespace line, currently
// classifies as data line
return 3 ;
}
if ( ch != '*' ) {
// This is a data line
return 1 ;
}
if ( i == eol_pos - 1 ) {
// Only a single *, error but make keyword line
return 4+3 ;
}
// This means we can have a second character
// if that is also a * this means a comment
// otherwise it is a keyword.
c = styler.SafeGetCharAt(i+1);
ch = static_cast<char>(LowerCase(c));
if ( ch == '*' ) {
return 8 ;
}
// At this point we know this is a keyword line
// the character at position i is a *
// it is not a comment line
char word[256] ;
int wlen = 0;
word[wlen] = '*' ;
wlen++ ;
i++ ;
while ( (i < eol_pos) && (wlen < 255) ) {
c = styler.SafeGetCharAt(i);
ch = static_cast<char>(LowerCase(c));
if ( (!IsSpace(c)) && (!IsIdentifier(c)) )
break ;
if ( IsIdentifier(c) ) {
word[wlen] = ch ;
wlen++ ;
}
i++ ;
}
word[wlen] = 0 ;
// Make a comparison
if ( !strcmp(word, "*step") ||
!strcmp(word, "*part") ||
!strcmp(word, "*instance") ||
!strcmp(word, "*assembly")) {
return 4+1 ;
}
if ( !strcmp(word, "*endstep") ||
!strcmp(word, "*endpart") ||
!strcmp(word, "*endinstance") ||
!strcmp(word, "*endassembly")) {
return 4+2 ;
}
return 4 ;
}
static void SafeSetLevel(Sci_Position line, int level, Accessor &styler)
{
if ( line < 0 )
return ;
int mask = ((~SC_FOLDLEVELHEADERFLAG) | (~SC_FOLDLEVELWHITEFLAG));
if ( (level & mask) < 0 )
return ;
if ( styler.LevelAt(line) != level )
styler.SetLevel(line, level) ;
}
static void FoldABAQUSDoc(Sci_PositionU startPos, Sci_Position length, int,
WordList *[], Accessor &styler) {
Sci_Position startLine = styler.GetLine(startPos) ;
Sci_Position endLine = styler.GetLine(startPos+length-1) ;
// bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
// We want to deal with all the cases
// To know the correct indentlevel, we need to look back to the
// previous command line indentation level
// order of formatting keyline datalines commentlines
Sci_Position beginData = -1 ;
Sci_Position beginComment = -1 ;
Sci_Position prvKeyLine = startLine ;
Sci_Position prvKeyLineTp = 0 ;
// Scan until we find the previous keyword line
// this will give us the level reference that we need
while ( prvKeyLine > 0 ) {
prvKeyLine-- ;
prvKeyLineTp = LineType(prvKeyLine, styler) ;
if ( prvKeyLineTp & 4 )
break ;
}
// Determine the base line level of all lines following
// the previous keyword
// new keyword lines are placed on this level
//if ( prvKeyLineTp & 4 ) {
int level = styler.LevelAt(prvKeyLine) & ~SC_FOLDLEVELHEADERFLAG ;
//}
// uncomment line below if weird behaviour continues
prvKeyLine = -1 ;
// Now start scanning over the lines.
for ( Sci_Position line = startLine; line <= endLine; line++ ) {
int lineType = LineType(line, styler) ;
// Check for comment line
if ( lineType == 8 ) {
if ( beginComment < 0 ) {
beginComment = line ;
}
}
// Check for data line
if ( (lineType == 1) || (lineType == 3) ) {
if ( beginData < 0 ) {
if ( beginComment >= 0 ) {
beginData = beginComment ;
} else {
beginData = line ;
}
}
beginComment = -1 ;
}
// Check for keywordline.
// As soon as a keyword line is encountered, we can set the
// levels of everything from the previous keyword line to this one
if ( lineType & 4 ) {
// this is a keyword, we can now place the previous keyword
// all its data lines and the remainder
// Write comments and data line
if ( beginComment < 0 ) {
beginComment = line ;
}
if ( beginData < 0 ) {
beginData = beginComment ;
if ( prvKeyLineTp != 5 )
SafeSetLevel(prvKeyLine, level, styler) ;
else
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
} else {
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
}
int datLevel = level + 1 ;
if ( !(prvKeyLineTp & 4) ) {
datLevel = level ;
}
for ( Sci_Position ll = beginData; ll < beginComment; ll++ )
SafeSetLevel(ll, datLevel, styler) ;
// The keyword we just found is going to be written at another level
// if we have a type 5 and type 6
if ( prvKeyLineTp == 5 ) {
level += 1 ;
}
if ( prvKeyLineTp == 6 ) {
level -= 1 ;
if ( level < 0 ) {
level = 0 ;
}
}
for ( Sci_Position lll = beginComment; lll < line; lll++ )
SafeSetLevel(lll, level, styler) ;
// wrap and reset
beginComment = -1 ;
beginData = -1 ;
prvKeyLine = line ;
prvKeyLineTp = lineType ;
}
}
if ( beginComment < 0 ) {
beginComment = endLine + 1 ;
} else {
// We need to find out whether this comment block is followed by
// a data line or a keyword line
const Sci_Position docLines = styler.GetLine(styler.Length() - 1);
for ( Sci_Position line = endLine + 1; line <= docLines; line++ ) {
Sci_Position lineType = LineType(line, styler) ;
if ( lineType != 8 ) {
if ( !(lineType & 4) ) {
beginComment = endLine + 1 ;
}
break ;
}
}
}
if ( beginData < 0 ) {
beginData = beginComment ;
if ( prvKeyLineTp != 5 )
SafeSetLevel(prvKeyLine, level, styler) ;
else
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
} else {
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
}
int datLevel = level + 1 ;
if ( !(prvKeyLineTp & 4) ) {
datLevel = level ;
}
for ( Sci_Position ll = beginData; ll < beginComment; ll++ )
SafeSetLevel(ll, datLevel, styler) ;
if ( prvKeyLineTp == 5 ) {
level += 1 ;
}
if ( prvKeyLineTp == 6 ) {
level -= 1 ;
}
for ( Sci_Position m = beginComment; m <= endLine; m++ )
SafeSetLevel(m, level, styler) ;
}
static const char * const abaqusWordListDesc[] = {
"processors",
"commands",
"slashommands",
"starcommands",
"arguments",
"functions",
0
};
LexerModule lmAbaqus(SCLEX_ABAQUS, ColouriseABAQUSDoc, "abaqus", FoldABAQUSDoc, abaqusWordListDesc);

View File

@ -0,0 +1,514 @@
// Scintilla source code edit control
/** @file LexAda.cxx
** Lexer for Ada 95
**/
// Copyright 2002 by Sergey Koshcheyev <sergey.k@seznam.cz>
// 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;
/*
* Interface
*/
static void ColouriseDocument(
Sci_PositionU startPos,
Sci_Position length,
int initStyle,
WordList *keywordlists[],
Accessor &styler);
static const char * const adaWordListDesc[] = {
"Keywords",
0
};
LexerModule lmAda(SCLEX_ADA, ColouriseDocument, "ada", NULL, adaWordListDesc);
/*
* Implementation
*/
// Functions that have apostropheStartsAttribute as a parameter set it according to whether
// an apostrophe encountered after processing the current token will start an attribute or
// a character literal.
static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL);
static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
static inline bool IsDelimiterCharacter(int ch);
static inline bool IsSeparatorOrDelimiterCharacter(int ch);
static bool IsValidIdentifier(const std::string& identifier);
static bool IsValidNumber(const std::string& number);
static inline bool IsWordStartCharacter(int ch);
static inline bool IsWordCharacter(int ch);
static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute) {
apostropheStartsAttribute = true;
sc.SetState(SCE_ADA_CHARACTER);
// Skip the apostrophe and one more character (so that '' is shown as non-terminated and '''
// is handled correctly)
sc.Forward();
sc.Forward();
ColouriseContext(sc, '\'', SCE_ADA_CHARACTEREOL);
}
static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL) {
while (!sc.atLineEnd && !sc.Match(chEnd)) {
sc.Forward();
}
if (!sc.atLineEnd) {
sc.ForwardSetState(SCE_ADA_DEFAULT);
} else {
sc.ChangeState(stateEOL);
}
}
static void ColouriseComment(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
// Apostrophe meaning is not changed, but the parameter is present for uniformity
sc.SetState(SCE_ADA_COMMENTLINE);
while (!sc.atLineEnd) {
sc.Forward();
}
}
static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) {
apostropheStartsAttribute = sc.Match (')');
sc.SetState(SCE_ADA_DELIMITER);
sc.ForwardSetState(SCE_ADA_DEFAULT);
}
static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
apostropheStartsAttribute = false;
sc.SetState(SCE_ADA_LABEL);
// Skip "<<"
sc.Forward();
sc.Forward();
std::string identifier;
while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
identifier += static_cast<char>(tolower(sc.ch));
sc.Forward();
}
// Skip ">>"
if (sc.Match('>', '>')) {
sc.Forward();
sc.Forward();
} else {
sc.ChangeState(SCE_ADA_ILLEGAL);
}
// If the name is an invalid identifier or a keyword, then make it invalid label
if (!IsValidIdentifier(identifier) || keywords.InList(identifier.c_str())) {
sc.ChangeState(SCE_ADA_ILLEGAL);
}
sc.SetState(SCE_ADA_DEFAULT);
}
static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) {
apostropheStartsAttribute = true;
std::string number;
sc.SetState(SCE_ADA_NUMBER);
// Get all characters up to a delimiter or a separator, including points, but excluding
// double points (ranges).
while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) {
number += static_cast<char>(sc.ch);
sc.Forward();
}
// Special case: exponent with sign
if ((sc.chPrev == 'e' || sc.chPrev == 'E') &&
(sc.ch == '+' || sc.ch == '-')) {
number += static_cast<char>(sc.ch);
sc.Forward ();
while (!IsSeparatorOrDelimiterCharacter(sc.ch)) {
number += static_cast<char>(sc.ch);
sc.Forward();
}
}
if (!IsValidNumber(number)) {
sc.ChangeState(SCE_ADA_ILLEGAL);
}
sc.SetState(SCE_ADA_DEFAULT);
}
static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute) {
apostropheStartsAttribute = true;
sc.SetState(SCE_ADA_STRING);
sc.Forward();
ColouriseContext(sc, '"', SCE_ADA_STRINGEOL);
}
static void ColouriseWhiteSpace(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
// Apostrophe meaning is not changed, but the parameter is present for uniformity
sc.SetState(SCE_ADA_DEFAULT);
sc.ForwardSetState(SCE_ADA_DEFAULT);
}
static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
apostropheStartsAttribute = true;
sc.SetState(SCE_ADA_IDENTIFIER);
std::string word;
while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
word += static_cast<char>(tolower(sc.ch));
sc.Forward();
}
if (!IsValidIdentifier(word)) {
sc.ChangeState(SCE_ADA_ILLEGAL);
} else if (keywords.InList(word.c_str())) {
sc.ChangeState(SCE_ADA_WORD);
if (word != "all") {
apostropheStartsAttribute = false;
}
}
sc.SetState(SCE_ADA_DEFAULT);
}
//
// ColouriseDocument
//
static void ColouriseDocument(
Sci_PositionU startPos,
Sci_Position length,
int initStyle,
WordList *keywordlists[],
Accessor &styler) {
WordList &keywords = *keywordlists[0];
StyleContext sc(startPos, length, initStyle, styler);
Sci_Position lineCurrent = styler.GetLine(startPos);
bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0;
while (sc.More()) {
if (sc.atLineEnd) {
// Go to the next line
sc.Forward();
lineCurrent++;
// Remember the line state for future incremental lexing
styler.SetLineState(lineCurrent, apostropheStartsAttribute);
// Don't continue any styles on the next line
sc.SetState(SCE_ADA_DEFAULT);
}
// Comments
if (sc.Match('-', '-')) {
ColouriseComment(sc, apostropheStartsAttribute);
// Strings
} else if (sc.Match('"')) {
ColouriseString(sc, apostropheStartsAttribute);
// Characters
} else if (sc.Match('\'') && !apostropheStartsAttribute) {
ColouriseCharacter(sc, apostropheStartsAttribute);
// Labels
} else if (sc.Match('<', '<')) {
ColouriseLabel(sc, keywords, apostropheStartsAttribute);
// Whitespace
} else if (IsASpace(sc.ch)) {
ColouriseWhiteSpace(sc, apostropheStartsAttribute);
// Delimiters
} else if (IsDelimiterCharacter(sc.ch)) {
ColouriseDelimiter(sc, apostropheStartsAttribute);
// Numbers
} else if (IsADigit(sc.ch) || sc.ch == '#') {
ColouriseNumber(sc, apostropheStartsAttribute);
// Keywords or identifiers
} else {
ColouriseWord(sc, keywords, apostropheStartsAttribute);
}
}
sc.Complete();
}
static inline bool IsDelimiterCharacter(int ch) {
switch (ch) {
case '&':
case '\'':
case '(':
case ')':
case '*':
case '+':
case ',':
case '-':
case '.':
case '/':
case ':':
case ';':
case '<':
case '=':
case '>':
case '|':
return true;
default:
return false;
}
}
static inline bool IsSeparatorOrDelimiterCharacter(int ch) {
return IsASpace(ch) || IsDelimiterCharacter(ch);
}
static bool IsValidIdentifier(const std::string& identifier) {
// First character can't be '_', so initialize the flag to true
bool lastWasUnderscore = true;
size_t length = identifier.length();
// Zero-length identifiers are not valid (these can occur inside labels)
if (length == 0) {
return false;
}
// Check for valid character at the start
if (!IsWordStartCharacter(identifier[0])) {
return false;
}
// Check for only valid characters and no double underscores
for (size_t i = 0; i < length; i++) {
if (!IsWordCharacter(identifier[i]) ||
(identifier[i] == '_' && lastWasUnderscore)) {
return false;
}
lastWasUnderscore = identifier[i] == '_';
}
// Check for underscore at the end
if (lastWasUnderscore == true) {
return false;
}
// All checks passed
return true;
}
static bool IsValidNumber(const std::string& number) {
size_t hashPos = number.find("#");
bool seenDot = false;
size_t i = 0;
size_t length = number.length();
if (length == 0)
return false; // Just in case
// Decimal number
if (hashPos == std::string::npos) {
bool canBeSpecial = false;
for (; i < length; i++) {
if (number[i] == '_') {
if (!canBeSpecial) {
return false;
}
canBeSpecial = false;
} else if (number[i] == '.') {
if (!canBeSpecial || seenDot) {
return false;
}
canBeSpecial = false;
seenDot = true;
} else if (IsADigit(number[i])) {
canBeSpecial = true;
} else {
break;
}
}
if (!canBeSpecial)
return false;
} else {
// Based number
bool canBeSpecial = false;
int base = 0;
// Parse base
for (; i < length; i++) {
int ch = number[i];
if (ch == '_') {
if (!canBeSpecial)
return false;
canBeSpecial = false;
} else if (IsADigit(ch)) {
base = base * 10 + (ch - '0');
if (base > 16)
return false;
canBeSpecial = true;
} else if (ch == '#' && canBeSpecial) {
break;
} else {
return false;
}
}
if (base < 2)
return false;
if (i == length)
return false;
i++; // Skip over '#'
// Parse number
canBeSpecial = false;
for (; i < length; i++) {
int ch = tolower(number[i]);
if (ch == '_') {
if (!canBeSpecial) {
return false;
}
canBeSpecial = false;
} else if (ch == '.') {
if (!canBeSpecial || seenDot) {
return false;
}
canBeSpecial = false;
seenDot = true;
} else if (IsADigit(ch)) {
if (ch - '0' >= base) {
return false;
}
canBeSpecial = true;
} else if (ch >= 'a' && ch <= 'f') {
if (ch - 'a' + 10 >= base) {
return false;
}
canBeSpecial = true;
} else if (ch == '#' && canBeSpecial) {
break;
} else {
return false;
}
}
if (i == length) {
return false;
}
i++;
}
// Exponent (optional)
if (i < length) {
if (number[i] != 'e' && number[i] != 'E')
return false;
i++; // Move past 'E'
if (i == length) {
return false;
}
if (number[i] == '+')
i++;
else if (number[i] == '-') {
if (seenDot) {
i++;
} else {
return false; // Integer literals should not have negative exponents
}
}
if (i == length) {
return false;
}
bool canBeSpecial = false;
for (; i < length; i++) {
if (number[i] == '_') {
if (!canBeSpecial) {
return false;
}
canBeSpecial = false;
} else if (IsADigit(number[i])) {
canBeSpecial = true;
} else {
return false;
}
}
if (!canBeSpecial)
return false;
}
// if i == length, number was parsed successfully.
return i == length;
}
static inline bool IsWordCharacter(int ch) {
return IsWordStartCharacter(ch) || IsADigit(ch);
}
static inline bool IsWordStartCharacter(int ch) {
return (IsASCII(ch) && isalpha(ch)) || ch == '_';
}

View File

@ -0,0 +1,393 @@
/******************************************************************
* LexAsciidoc.cxx
*
* A simple Asciidoc lexer for scintilla.
*
* Based on the LexMarkdown.cxx by Jon Strait - jstrait@moonloop.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 <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;
namespace {
typedef struct {
bool start;
int len1;
int len2;
const char *name;
} MacroItem;
static const MacroItem MacroList[] = {
// Directives
{true, 5, 2, "ifdef::"},
{true, 6, 2, "ifeval::"},
{true, 6, 2, "ifndef::"},
{true, 5, 2, "endif::"},
// Macros
{true, 5, 2, "audio::"},
{true, 7, 2, "include::"},
{true, 5, 2, "image::"},
{true, 5, 2, "video::"},
{false, 8, 1, "asciimath:"},
{false, 3, 1, "btn:"},
{false, 5, 1, "image:"},
{false, 3, 1, "kbd:"},
{false, 9, 1, "latexmath:"},
{false, 4, 1, "link:"},
{false, 6, 1, "mailto:"},
{false, 4, 1, "menu:"},
{false, 4, 1, "pass:"},
{false, 4, 1, "stem:"},
{false, 4, 1, "xref:"},
// Admonitions
{true, 7, 1, "CAUTION:"},
{true, 9, 1, "IMPORTANT:"},
{true, 4, 1, "NOTE:"},
{true, 3, 1, "TIP:"},
{true, 7, 1, "WARNING:"},
{false, 0, 0, NULL}
};
constexpr bool IsNewline(const int ch) {
// sc.GetRelative(i) returns '\0' if out of range
return (ch == '\n' || ch == '\r' || ch == '\0');
}
}
static bool AtTermStart(StyleContext &sc) {
return sc.currentPos == 0 || sc.chPrev == 0 || isspacechar(sc.chPrev);
}
static void ColorizeAsciidocDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList **, Accessor &styler) {
bool freezeCursor = false;
StyleContext sc(startPos, static_cast<Sci_PositionU>(length), initStyle, styler);
while (sc.More()) {
// Skip past escaped characters
if (sc.ch == '\\') {
sc.Forward();
continue;
}
// Skip newline.
if (IsNewline(sc.ch)) {
// Newline doesn't end blocks
if (sc.state != SCE_ASCIIDOC_CODEBK && \
sc.state != SCE_ASCIIDOC_PASSBK && \
sc.state != SCE_ASCIIDOC_COMMENTBK && \
sc.state != SCE_ASCIIDOC_LITERALBK) {
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
sc.Forward();
continue;
}
// Conditional state-based actions
switch (sc.state) {
// Strong
case SCE_ASCIIDOC_STRONG1:
if (sc.ch == '*' && sc.chPrev != ' ') {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_DEFAULT);
freezeCursor = true;
}
break;
case SCE_ASCIIDOC_STRONG2:
if (sc.Match("**") && sc.chPrev != ' ') {
sc.Forward(2);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
freezeCursor = true;
}
break;
// Emphasis
case SCE_ASCIIDOC_EM1:
if (sc.ch == '_' && sc.chPrev != ' ') {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_DEFAULT);
freezeCursor = true;
}
break;
case SCE_ASCIIDOC_EM2:
if (sc.Match("__") && sc.chPrev != ' ') {
sc.Forward(2);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
freezeCursor = true;
}
break;
// Link
case SCE_ASCIIDOC_LINK:
if (sc.ch == ']' && sc.chPrev != '\\') {
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Code block
case SCE_ASCIIDOC_CODEBK:
if (sc.atLineStart && sc.Match("----") && IsNewline(sc.GetRelative(4))) {
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Passthrough block
case SCE_ASCIIDOC_PASSBK:
if (sc.atLineStart && sc.Match("++++") && IsNewline(sc.GetRelative(4))) {
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Comment block
case SCE_ASCIIDOC_COMMENTBK:
if (sc.atLineStart && sc.Match("////") && IsNewline(sc.GetRelative(4))) {
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Literal
case SCE_ASCIIDOC_LITERAL:
if (sc.ch == '+' && sc.chPrev != '\\') {
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Literal block
case SCE_ASCIIDOC_LITERALBK:
if (sc.atLineStart && sc.Match("....") && IsNewline(sc.GetRelative(4))) {
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Attribute
case SCE_ASCIIDOC_ATTRIB:
if (sc.ch == ':' && sc.chPrev != ' ' && sc.chNext == ' ') {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_ATTRIBVAL);
}
break;
// Macro
case SCE_ASCIIDOC_MACRO:
if (sc.ch == ']' && sc.chPrev != '\\') {
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Default
case SCE_ASCIIDOC_DEFAULT:
// Headers
if (sc.atLineStart && sc.Match("====== ")) {
sc.SetState(SCE_ASCIIDOC_HEADER6);
sc.Forward(6);
}
else if (sc.atLineStart && sc.Match("===== ")) {
sc.SetState(SCE_ASCIIDOC_HEADER5);
sc.Forward(5);
}
else if (sc.atLineStart && sc.Match("==== ")) {
sc.SetState(SCE_ASCIIDOC_HEADER4);
sc.Forward(4);
}
else if (sc.atLineStart && sc.Match("=== ")) {
sc.SetState(SCE_ASCIIDOC_HEADER3);
sc.Forward(3);
}
else if (sc.atLineStart && sc.Match("== ")) {
sc.SetState(SCE_ASCIIDOC_HEADER2);
sc.Forward(2);
}
else if (sc.atLineStart && sc.Match("= ")) {
sc.SetState(SCE_ASCIIDOC_HEADER1);
sc.Forward(1);
}
// Unordered list item
else if (sc.atLineStart && sc.Match("****** ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(6);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("***** ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(5);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("**** ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("*** ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(3);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("** ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(2);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("* ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(1);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
// Ordered list item
else if (sc.atLineStart && sc.Match("...... ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(6);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("..... ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(5);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match(".... ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("... ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(3);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match(".. ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(2);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match(". ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(1);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
// Blockquote
else if (sc.atLineStart && sc.Match("> ")) {
sc.SetState(SCE_ASCIIDOC_BLOCKQUOTE);
sc.Forward();
}
// Link
else if (!sc.atLineStart && sc.ch == '[' && sc.chPrev != '\\' && sc.chNext != ' ') {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_LINK);
freezeCursor = true;
}
// Code block
else if (sc.atLineStart && sc.Match("----") && IsNewline(sc.GetRelative(4))) {
sc.SetState(SCE_ASCIIDOC_CODEBK);
sc.Forward(4);
}
// Passthrough block
else if (sc.atLineStart && sc.Match("++++") && IsNewline(sc.GetRelative(4))) {
sc.SetState(SCE_ASCIIDOC_PASSBK);
sc.Forward(4);
}
// Comment block
else if (sc.atLineStart && sc.Match("////") && IsNewline(sc.GetRelative(4))) {
sc.SetState(SCE_ASCIIDOC_COMMENTBK);
sc.Forward(4);
}
// Comment
else if (sc.atLineStart && sc.Match("//")) {
sc.SetState(SCE_ASCIIDOC_COMMENT);
sc.Forward();
}
// Literal
else if (sc.ch == '+' && sc.chPrev != '\\' && sc.chNext != ' ' && AtTermStart(sc)) {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_LITERAL);
freezeCursor = true;
}
// Literal block
else if (sc.atLineStart && sc.Match("....") && IsNewline(sc.GetRelative(4))) {
sc.SetState(SCE_ASCIIDOC_LITERALBK);
sc.Forward(4);
}
// Attribute
else if (sc.atLineStart && sc.ch == ':' && sc.chNext != ' ') {
sc.SetState(SCE_ASCIIDOC_ATTRIB);
}
// Strong
else if (sc.Match("**") && sc.GetRelative(2) != ' ') {
sc.SetState(SCE_ASCIIDOC_STRONG2);
sc.Forward();
}
else if (sc.ch == '*' && sc.chNext != ' ' && AtTermStart(sc)) {
sc.SetState(SCE_ASCIIDOC_STRONG1);
}
// Emphasis
else if (sc.Match("__") && sc.GetRelative(2) != ' ') {
sc.SetState(SCE_ASCIIDOC_EM2);
sc.Forward();
}
else if (sc.ch == '_' && sc.chNext != ' ' && AtTermStart(sc)) {
sc.SetState(SCE_ASCIIDOC_EM1);
}
// Macro
else if (sc.atLineStart && sc.ch == '[' && sc.chNext != ' ') {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_MACRO);
freezeCursor = true;
}
else {
int i = 0;
bool found = false;
while (!found && MacroList[i].name != NULL) {
if (MacroList[i].start)
found = sc.atLineStart && sc.Match(MacroList[i].name);
else
found = sc.Match(MacroList[i].name);
if (found) {
sc.SetState(SCE_ASCIIDOC_MACRO);
sc.Forward(MacroList[i].len1);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
if (MacroList[i].len2 > 1)
sc.Forward(MacroList[i].len2 - 1);
}
i++;
}
}
break;
}
// Advance if not holding back the cursor for this iteration.
if (!freezeCursor)
sc.Forward();
freezeCursor = false;
}
sc.Complete();
}
LexerModule lmAsciidoc(SCLEX_ASCIIDOC, ColorizeAsciidocDoc, "asciidoc");

View File

@ -0,0 +1,481 @@
// Scintilla source code edit control
/** @file LexAsm.cxx
** Lexer for Assembler, just for the MASM syntax
** Written by The Black Horus
** Enhancements and NASM stuff by Kein-Hong Man, 2003-10
** SCE_ASM_COMMENTBLOCK and SCE_ASM_CHARACTER are for future GNU as colouring
** Converted to lexer object and added further folding features/properties by "Udo Lechner" <dlchnr(at)gmx(dot)net>
**/
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// 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 <map>
#include <set>
#include <functional>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "DefaultLexer.h"
using namespace Scintilla;
using namespace Lexilla;
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 == '.' ||
ch == '%' || ch == '@' || ch == '$' || ch == '?');
}
static inline bool IsAsmOperator(const 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 == ':')
return true;
return false;
}
static bool IsStreamCommentStyle(int style) {
return style == SCE_ASM_COMMENTDIRECTIVE || style == SCE_ASM_COMMENTBLOCK;
}
static inline int LowerCase(int c) {
if (c >= 'A' && c <= 'Z')
return 'a' + c - 'A';
return c;
}
// An individual named option for use in an OptionSet
// Options used for LexerAsm
struct OptionsAsm {
std::string delimiter;
bool fold;
bool foldSyntaxBased;
bool foldCommentMultiline;
bool foldCommentExplicit;
std::string foldExplicitStart;
std::string foldExplicitEnd;
bool foldExplicitAnywhere;
bool foldCompact;
std::string commentChar;
OptionsAsm() {
delimiter = "";
fold = false;
foldSyntaxBased = true;
foldCommentMultiline = false;
foldCommentExplicit = false;
foldExplicitStart = "";
foldExplicitEnd = "";
foldExplicitAnywhere = false;
foldCompact = true;
commentChar = "";
}
};
static const char * const asmWordListDesc[] = {
"CPU instructions",
"FPU instructions",
"Registers",
"Directives",
"Directive operands",
"Extended instructions",
"Directives4Foldstart",
"Directives4Foldend",
0
};
struct OptionSetAsm : public OptionSet<OptionsAsm> {
OptionSetAsm() {
DefineProperty("lexer.asm.comment.delimiter", &OptionsAsm::delimiter,
"Character used for COMMENT directive's delimiter, replacing the standard \"~\".");
DefineProperty("fold", &OptionsAsm::fold);
DefineProperty("fold.asm.syntax.based", &OptionsAsm::foldSyntaxBased,
"Set this property to 0 to disable syntax based folding.");
DefineProperty("fold.asm.comment.multiline", &OptionsAsm::foldCommentMultiline,
"Set this property to 1 to enable folding multi-line comments.");
DefineProperty("fold.asm.comment.explicit", &OptionsAsm::foldCommentExplicit,
"This option enables folding explicit fold points when using the Asm lexer. "
"Explicit fold points allows adding extra folding by placing a ;{ comment at the start and a ;} "
"at the end of a section that should fold.");
DefineProperty("fold.asm.explicit.start", &OptionsAsm::foldExplicitStart,
"The string to use for explicit fold start points, replacing the standard ;{.");
DefineProperty("fold.asm.explicit.end", &OptionsAsm::foldExplicitEnd,
"The string to use for explicit fold end points, replacing the standard ;}.");
DefineProperty("fold.asm.explicit.anywhere", &OptionsAsm::foldExplicitAnywhere,
"Set this property to 1 to enable explicit fold points anywhere, not just in line comments.");
DefineProperty("fold.compact", &OptionsAsm::foldCompact);
DefineProperty("lexer.as.comment.character", &OptionsAsm::commentChar,
"Overrides the default comment character (which is ';' for asm and '#' for as).");
DefineWordListSets(asmWordListDesc);
}
};
class LexerAsm : public DefaultLexer {
WordList cpuInstruction;
WordList mathInstruction;
WordList registers;
WordList directive;
WordList directiveOperand;
WordList extInstruction;
WordList directives4foldstart;
WordList directives4foldend;
OptionsAsm options;
OptionSetAsm osAsm;
int commentChar;
public:
LexerAsm(const char *languageName_, int language_, int commentChar_) : DefaultLexer(languageName_, language_) {
commentChar = commentChar_;
}
virtual ~LexerAsm() {
}
void SCI_METHOD Release() override {
delete this;
}
int SCI_METHOD Version() const override {
return lvRelease5;
}
const char * SCI_METHOD PropertyNames() override {
return osAsm.PropertyNames();
}
int SCI_METHOD PropertyType(const char *name) override {
return osAsm.PropertyType(name);
}
const char * SCI_METHOD DescribeProperty(const char *name) override {
return osAsm.DescribeProperty(name);
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
const char * SCI_METHOD PropertyGet(const char *key) override {
return osAsm.PropertyGet(key);
}
const char * SCI_METHOD DescribeWordListSets() override {
return osAsm.DescribeWordListSets();
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void * SCI_METHOD PrivateCall(int, void *) override {
return 0;
}
static ILexer5 *LexerFactoryAsm() {
return new LexerAsm("asm", SCLEX_ASM, ';');
}
static ILexer5 *LexerFactoryAs() {
return new LexerAsm("as", SCLEX_AS, '#');
}
};
Sci_Position SCI_METHOD LexerAsm::PropertySet(const char *key, const char *val) {
if (osAsm.PropertySet(&options, key, val)) {
return 0;
}
return -1;
}
Sci_Position SCI_METHOD LexerAsm::WordListSet(int n, const char *wl) {
WordList *wordListN = 0;
switch (n) {
case 0:
wordListN = &cpuInstruction;
break;
case 1:
wordListN = &mathInstruction;
break;
case 2:
wordListN = &registers;
break;
case 3:
wordListN = &directive;
break;
case 4:
wordListN = &directiveOperand;
break;
case 5:
wordListN = &extInstruction;
break;
case 6:
wordListN = &directives4foldstart;
break;
case 7:
wordListN = &directives4foldend;
break;
}
Sci_Position firstModification = -1;
if (wordListN) {
if (wordListN->Set(wl)) {
firstModification = 0;
}
}
return firstModification;
}
void SCI_METHOD LexerAsm::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
LexAccessor styler(pAccess);
const char commentCharacter = options.commentChar.empty() ?
commentChar : options.commentChar.front();
// Do not leak onto next line
if (initStyle == SCE_ASM_STRINGEOL)
initStyle = SCE_ASM_DEFAULT;
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward())
{
if (sc.atLineStart) {
switch (sc.state) {
case SCE_ASM_STRING:
case SCE_ASM_CHARACTER:
// Prevent SCE_ASM_STRINGEOL from leaking back to previous line
sc.SetState(sc.state);
break;
case SCE_ASM_COMMENT:
sc.SetState(SCE_ASM_DEFAULT);
break;
default:
break;
}
}
// 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_ASM_OPERATOR) {
if (!IsAsmOperator(sc.ch)) {
sc.SetState(SCE_ASM_DEFAULT);
}
} else if (sc.state == SCE_ASM_NUMBER) {
if (!IsAWordChar(sc.ch)) {
sc.SetState(SCE_ASM_DEFAULT);
}
} else if (sc.state == SCE_ASM_IDENTIFIER) {
if (!IsAWordChar(sc.ch) ) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
bool IsDirective = false;
if (cpuInstruction.InList(s)) {
sc.ChangeState(SCE_ASM_CPUINSTRUCTION);
} else if (mathInstruction.InList(s)) {
sc.ChangeState(SCE_ASM_MATHINSTRUCTION);
} else if (registers.InList(s)) {
sc.ChangeState(SCE_ASM_REGISTER);
} else if (directive.InList(s)) {
sc.ChangeState(SCE_ASM_DIRECTIVE);
IsDirective = true;
} else if (directiveOperand.InList(s)) {
sc.ChangeState(SCE_ASM_DIRECTIVEOPERAND);
} else if (extInstruction.InList(s)) {
sc.ChangeState(SCE_ASM_EXTINSTRUCTION);
}
sc.SetState(SCE_ASM_DEFAULT);
if (IsDirective && !strcmp(s, "comment")) {
char delimiter = options.delimiter.empty() ? '~' : options.delimiter.c_str()[0];
while (IsASpaceOrTab(sc.ch) && !sc.atLineEnd) {
sc.ForwardSetState(SCE_ASM_DEFAULT);
}
if (sc.ch == delimiter) {
sc.SetState(SCE_ASM_COMMENTDIRECTIVE);
}
}
}
} else if (sc.state == SCE_ASM_COMMENTDIRECTIVE) {
char delimiter = options.delimiter.empty() ? '~' : options.delimiter.c_str()[0];
if (sc.ch == delimiter) {
while (!sc.MatchLineEnd()) {
sc.Forward();
}
sc.SetState(SCE_ASM_DEFAULT);
}
} else if (sc.state == SCE_ASM_STRING) {
if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_ASM_DEFAULT);
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_ASM_STRINGEOL);
sc.ForwardSetState(SCE_ASM_DEFAULT);
}
} else if (sc.state == SCE_ASM_CHARACTER) {
if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\'') {
sc.ForwardSetState(SCE_ASM_DEFAULT);
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_ASM_STRINGEOL);
sc.ForwardSetState(SCE_ASM_DEFAULT);
}
}
// Determine if a new state should be entered.
if (sc.state == SCE_ASM_DEFAULT) {
if (sc.ch == commentCharacter) {
sc.SetState(SCE_ASM_COMMENT);
} else if (IsASCII(sc.ch) && (isdigit(sc.ch) || (sc.ch == '.' && IsASCII(sc.chNext) && isdigit(sc.chNext)))) {
sc.SetState(SCE_ASM_NUMBER);
} else if (IsAWordStart(sc.ch)) {
sc.SetState(SCE_ASM_IDENTIFIER);
} else if (sc.ch == '\"') {
sc.SetState(SCE_ASM_STRING);
} else if (sc.ch == '\'') {
sc.SetState(SCE_ASM_CHARACTER);
} else if (IsAsmOperator(sc.ch)) {
sc.SetState(SCE_ASM_OPERATOR);
}
}
}
sc.Complete();
}
// 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".
void SCI_METHOD LexerAsm::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
if (!options.fold)
return;
LexAccessor styler(pAccess);
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelCurrent = SC_FOLDLEVELBASE;
if (lineCurrent > 0)
levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
int levelNext = levelCurrent;
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
int style = initStyle;
char word[100];
int wordlen = 0;
const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty();
for (Sci_PositionU 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 (options.foldCommentMultiline && 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 (options.foldCommentExplicit && ((style == SCE_ASM_COMMENT) || options.foldExplicitAnywhere)) {
if (userDefinedFoldMarkers) {
if (styler.Match(i, options.foldExplicitStart.c_str())) {
levelNext++;
} else if (styler.Match(i, options.foldExplicitEnd.c_str())) {
levelNext--;
}
} else {
if (ch == ';') {
if (chNext == '{') {
levelNext++;
} else if (chNext == '}') {
levelNext--;
}
}
}
}
if (options.foldSyntaxBased && (style == SCE_ASM_DIRECTIVE)) {
word[wordlen++] = static_cast<char>(LowerCase(ch));
if (wordlen == 100) { // prevent overflow
word[0] = '\0';
wordlen = 1;
}
if (styleNext != SCE_ASM_DIRECTIVE) { // reading directive ready
word[wordlen] = '\0';
wordlen = 0;
if (directives4foldstart.InList(word)) {
levelNext++;
} else if (directives4foldend.InList(word)){
levelNext--;
}
}
}
if (!IsASpace(ch))
visibleChars++;
if (atEOL || (i == endPos-1)) {
int levelUse = levelCurrent;
int lev = levelUse | levelNext << 16;
if (visibleChars == 0 && options.foldCompact)
lev |= SC_FOLDLEVELWHITEFLAG;
if (levelUse < levelNext)
lev |= SC_FOLDLEVELHEADERFLAG;
if (lev != styler.LevelAt(lineCurrent)) {
styler.SetLevel(lineCurrent, lev);
}
lineCurrent++;
levelCurrent = levelNext;
if (atEOL && (i == static_cast<Sci_PositionU>(styler.Length() - 1))) {
// There is an empty line at end of file so give it same level and empty
styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
}
visibleChars = 0;
}
}
}
LexerModule lmAsm(SCLEX_ASM, LexerAsm::LexerFactoryAsm, "asm", asmWordListDesc);
LexerModule lmAs(SCLEX_AS, LexerAsm::LexerFactoryAs, "as", asmWordListDesc);

View File

@ -0,0 +1,189 @@
// Scintilla source code edit control
/** @file LexAsn1.cxx
** Lexer for ASN.1
**/
// Copyright 2004 by Herr Pfarrer rpfarrer <at> yahoo <dot> de
// Last Updated: 20/07/2004
// 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 <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;
// Some char test functions
static bool isAsn1Number(int ch)
{
return (ch >= '0' && ch <= '9');
}
static bool isAsn1Letter(int ch)
{
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
}
static bool isAsn1Char(int ch)
{
return (ch == '-' ) || isAsn1Number(ch) || isAsn1Letter (ch);
}
//
// Function determining the color of a given code portion
// Based on a "state"
//
static void ColouriseAsn1Doc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordLists[], Accessor &styler)
{
// The keywords
WordList &Keywords = *keywordLists[0];
WordList &Attributes = *keywordLists[1];
WordList &Descriptors = *keywordLists[2];
WordList &Types = *keywordLists[3];
// Parse the whole buffer character by character using StyleContext
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward())
{
// The state engine
switch (sc.state)
{
case SCE_ASN1_DEFAULT: // Plain characters
asn1_default:
if (sc.ch == '-' && sc.chNext == '-')
// A comment begins here
sc.SetState(SCE_ASN1_COMMENT);
else if (sc.ch == '"')
// A string begins here
sc.SetState(SCE_ASN1_STRING);
else if (isAsn1Number (sc.ch))
// A number starts here (identifier should start with a letter in ASN.1)
sc.SetState(SCE_ASN1_SCALAR);
else if (isAsn1Char (sc.ch))
// An identifier starts here (identifier always start with a letter)
sc.SetState(SCE_ASN1_IDENTIFIER);
else if (sc.ch == ':')
// A ::= operator starts here
sc.SetState(SCE_ASN1_OPERATOR);
break;
case SCE_ASN1_COMMENT: // A comment
if (sc.ch == '\r' || sc.ch == '\n')
// A comment ends here
sc.SetState(SCE_ASN1_DEFAULT);
break;
case SCE_ASN1_IDENTIFIER: // An identifier (keyword, attribute, descriptor or type)
if (!isAsn1Char (sc.ch))
{
// The end of identifier is here: we can look for it in lists by now and change its state
char s[100];
sc.GetCurrent(s, sizeof(s));
if (Keywords.InList(s))
// It's a keyword, change its state
sc.ChangeState(SCE_ASN1_KEYWORD);
else if (Attributes.InList(s))
// It's an attribute, change its state
sc.ChangeState(SCE_ASN1_ATTRIBUTE);
else if (Descriptors.InList(s))
// It's a descriptor, change its state
sc.ChangeState(SCE_ASN1_DESCRIPTOR);
else if (Types.InList(s))
// It's a type, change its state
sc.ChangeState(SCE_ASN1_TYPE);
// Set to default now
sc.SetState(SCE_ASN1_DEFAULT);
}
break;
case SCE_ASN1_STRING: // A string delimited by ""
if (sc.ch == '"')
{
// A string ends here
sc.ForwardSetState(SCE_ASN1_DEFAULT);
// To correctly manage a char sticking to the string quote
goto asn1_default;
}
break;
case SCE_ASN1_SCALAR: // A plain number
if (!isAsn1Number (sc.ch))
// A number ends here
sc.SetState(SCE_ASN1_DEFAULT);
break;
case SCE_ASN1_OPERATOR: // The affectation operator ::= and wath follows (eg: ::= { org 6 } OID or ::= 12 trap)
if (sc.ch == '{')
{
// An OID definition starts here: enter the sub loop
for (; sc.More(); sc.Forward())
{
if (isAsn1Number (sc.ch) && (!isAsn1Char (sc.chPrev) || isAsn1Number (sc.chPrev)))
// The OID number is highlighted
sc.SetState(SCE_ASN1_OID);
else if (isAsn1Char (sc.ch))
// The OID parent identifier is plain
sc.SetState(SCE_ASN1_IDENTIFIER);
else
sc.SetState(SCE_ASN1_DEFAULT);
if (sc.ch == '}')
// Here ends the OID and the operator sub loop: go back to main loop
break;
}
}
else if (isAsn1Number (sc.ch))
{
// A trap number definition starts here: enter the sub loop
for (; sc.More(); sc.Forward())
{
if (isAsn1Number (sc.ch))
// The trap number is highlighted
sc.SetState(SCE_ASN1_OID);
else
{
// The number ends here: go back to main loop
sc.SetState(SCE_ASN1_DEFAULT);
break;
}
}
}
else if (sc.ch != ':' && sc.ch != '=' && sc.ch != ' ')
// The operator doesn't imply an OID definition nor a trap, back to main loop
goto asn1_default; // To be sure to handle actually the state change
break;
}
}
sc.Complete();
}
static void FoldAsn1Doc(Sci_PositionU, Sci_Position, int, WordList *[], Accessor &styler)
{
// No folding enabled, no reason to continue...
if( styler.GetPropertyInt("fold") == 0 )
return;
// No folding implemented: doesn't make sense for ASN.1
}
static const char * const asn1WordLists[] = {
"Keywords",
"Attributes",
"Descriptors",
"Types",
0, };
LexerModule lmAsn1(SCLEX_ASN1, ColouriseAsn1Doc, "asn1", FoldAsn1Doc, asn1WordLists);

View File

@ -0,0 +1,995 @@
// Scintilla source code edit control
/** @file LexBaan.cxx
** Lexer for Baan.
** Based heavily on LexCPP.cxx
**/
// Copyright 2001- by Vamsi Potluru <vamsi@who.net> & Praveen Ambekar <ambekarpraveen@yahoo.com>
// Maintainer Email: oirfeodent@yahoo.co.in
// The License.txt file describes the conditions under which this software may be distributed.
// C standard library
#include <stdlib.h>
#include <string.h>
// C++ wrappers of C standard library
#include <cassert>
// C++ standard library
#include <string>
#include <string_view>
#include <map>
#include <functional>
// Scintilla headers
// Non-platform-specific headers
// include
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
// lexlib
#include "WordList.h"
#include "LexAccessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "DefaultLexer.h"
using namespace Scintilla;
using namespace Lexilla;
namespace {
// Use an unnamed namespace to protect the functions and classes from name conflicts
// Options used for LexerBaan
struct OptionsBaan {
bool fold;
bool foldComment;
bool foldPreprocessor;
bool foldCompact;
bool baanFoldSyntaxBased;
bool baanFoldKeywordsBased;
bool baanFoldSections;
bool baanFoldInnerLevel;
bool baanStylingWithinPreprocessor;
OptionsBaan() {
fold = false;
foldComment = false;
foldPreprocessor = false;
foldCompact = false;
baanFoldSyntaxBased = false;
baanFoldKeywordsBased = false;
baanFoldSections = false;
baanFoldInnerLevel = false;
baanStylingWithinPreprocessor = false;
}
};
const char *const baanWordLists[] = {
"Baan & BaanSQL Reserved Keywords ",
"Baan Standard functions",
"Baan Functions Abridged",
"Baan Main Sections ",
"Baan Sub Sections",
"PreDefined Variables",
"PreDefined Attributes",
"Enumerates",
0,
};
struct OptionSetBaan : public OptionSet<OptionsBaan> {
OptionSetBaan() {
DefineProperty("fold", &OptionsBaan::fold);
DefineProperty("fold.comment", &OptionsBaan::foldComment);
DefineProperty("fold.preprocessor", &OptionsBaan::foldPreprocessor);
DefineProperty("fold.compact", &OptionsBaan::foldCompact);
DefineProperty("fold.baan.syntax.based", &OptionsBaan::baanFoldSyntaxBased,
"Set this property to 0 to disable syntax based folding, which is folding based on '{' & '('.");
DefineProperty("fold.baan.keywords.based", &OptionsBaan::baanFoldKeywordsBased,
"Set this property to 0 to disable keywords based folding, which is folding based on "
" for, if, on (case), repeat, select, while and fold ends based on endfor, endif, endcase, until, endselect, endwhile respectively."
"Also folds declarations which are grouped together.");
DefineProperty("fold.baan.sections", &OptionsBaan::baanFoldSections,
"Set this property to 0 to disable folding of Main Sections as well as Sub Sections.");
DefineProperty("fold.baan.inner.level", &OptionsBaan::baanFoldInnerLevel,
"Set this property to 1 to enable folding of inner levels of select statements."
"Disabled by default. case and if statements are also eligible" );
DefineProperty("lexer.baan.styling.within.preprocessor", &OptionsBaan::baanStylingWithinPreprocessor,
"For Baan code, determines whether all preprocessor code is styled in the "
"preprocessor style (0, the default) or only from the initial # to the end "
"of the command word(1).");
DefineWordListSets(baanWordLists);
}
};
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '$');
}
static inline bool IsAnOperator(int ch) {
if (IsAlphaNumeric(ch))
return false;
if (ch == '#' || ch == '^' || ch == '&' || ch == '*' ||
ch == '(' || 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 inline int IsAnyOtherIdentifier(char *s, Sci_Position sLength) {
/* IsAnyOtherIdentifier uses standard templates used in baan.
The matching template is shown as comments just above the return condition.
^ - refers to any character [a-z].
# - refers to any number [0-9].
Other characters shown are compared as is.
Tried implementing with Regex... it was too complicated for me.
Any other implementation suggestion welcome.
*/
switch (sLength) {
case 8:
if (isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
//^^^^^###
return(SCE_BAAN_TABLEDEF);
}
break;
case 9:
if (s[0] == 't' && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && isalpha(s[5]) && IsADigit(s[6]) && IsADigit(s[7]) && IsADigit(s[8])) {
//t^^^^^###
return(SCE_BAAN_TABLEDEF);
}
else if (s[8] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
//^^^^^###.
return(SCE_BAAN_TABLESQL);
}
break;
case 13:
if (s[8] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
//^^^^^###.****
return(SCE_BAAN_TABLESQL);
}
else if (s[0] == 'r' && s[1] == 'c' && s[2] == 'd' && s[3] == '.' && s[4] == 't' && isalpha(s[5]) && isalpha(s[6]) && isalpha(s[7]) && isalpha(s[8]) && isalpha(s[9]) && IsADigit(s[10]) && IsADigit(s[11]) && IsADigit(s[12])) {
//rcd.t^^^^^###
return(SCE_BAAN_TABLEDEF);
}
break;
case 14:
case 15:
if (s[8] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
if (s[13] != ':') {
//^^^^^###.******
return(SCE_BAAN_TABLESQL);
}
}
break;
case 16:
case 17:
if (s[8] == '.' && s[9] == '_' && s[10] == 'i' && s[11] == 'n' && s[12] == 'd' && s[13] == 'e' && s[14] == 'x' && IsADigit(s[15]) && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
//^^^^^###._index##
return(SCE_BAAN_TABLEDEF);
}
else if (s[8] == '.' && s[9] == '_' && s[10] == 'c' && s[11] == 'o' && s[12] == 'm' && s[13] == 'p' && s[14] == 'n' && s[15] == 'r' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
//^^^^^###._compnr
return(SCE_BAAN_TABLEDEF);
}
break;
default:
break;
}
if (sLength > 14 && s[5] == '.' && s[6] == 'd' && s[7] == 'l' && s[8] == 'l' && s[13] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[9]) && IsADigit(s[10]) && IsADigit(s[11]) && IsADigit(s[12])) {
//^^^^^.dll####.
return(SCE_BAAN_FUNCTION);
}
else if (sLength > 15 && s[2] == 'i' && s[3] == 'n' && s[4] == 't' && s[5] == '.' && s[6] == 'd' && s[7] == 'l' && s[8] == 'l' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[9]) && isalpha(s[10]) && isalpha(s[11]) && isalpha(s[12]) && isalpha(s[13])) {
//^^int.dll^^^^^.
return(SCE_BAAN_FUNCTION);
}
else if (sLength > 11 && s[0] == 'i' && s[10] == '.' && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && isalpha(s[5]) && IsADigit(s[6]) && IsADigit(s[7]) && IsADigit(s[8]) && IsADigit(s[9])) {
//i^^^^^####.
return(SCE_BAAN_FUNCTION);
}
return(SCE_BAAN_DEFAULT);
}
static bool IsCommentLine(Sci_Position line, LexAccessor &styler) {
Sci_Position pos = styler.LineStart(line);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eol_pos; i++) {
char ch = styler[i];
int style = styler.StyleAt(i);
if (ch == '|' && style == SCE_BAAN_COMMENT)
return true;
else if (!IsASpaceOrTab(ch))
return false;
}
return false;
}
static bool IsPreProcLine(Sci_Position line, LexAccessor &styler) {
Sci_Position pos = styler.LineStart(line);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eol_pos; i++) {
char ch = styler[i];
int style = styler.StyleAt(i);
if (ch == '#' && style == SCE_BAAN_PREPROCESSOR) {
if (styler.Match(i, "#elif") || styler.Match(i, "#else") || styler.Match(i, "#endif")
|| styler.Match(i, "#if") || styler.Match(i, "#ifdef") || styler.Match(i, "#ifndef"))
// Above PreProcessors has a seperate fold mechanism.
return false;
else
return true;
}
else if (ch == '^')
return true;
else if (!IsASpaceOrTab(ch))
return false;
}
return false;
}
static int mainOrSubSectionLine(Sci_Position line, LexAccessor &styler) {
Sci_Position pos = styler.LineStart(line);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eol_pos; i++) {
char ch = styler[i];
int style = styler.StyleAt(i);
if (style == SCE_BAAN_WORD5 || style == SCE_BAAN_WORD4)
return style;
else if (IsASpaceOrTab(ch))
continue;
else
break;
}
return 0;
}
static bool priorSectionIsSubSection(Sci_Position line, LexAccessor &styler){
while (line > 0) {
Sci_Position pos = styler.LineStart(line);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eol_pos; i++) {
char ch = styler[i];
int style = styler.StyleAt(i);
if (style == SCE_BAAN_WORD4)
return true;
else if (style == SCE_BAAN_WORD5)
return false;
else if (IsASpaceOrTab(ch))
continue;
else
break;
}
line--;
}
return false;
}
static bool nextSectionIsSubSection(Sci_Position line, LexAccessor &styler) {
while (line > 0) {
Sci_Position pos = styler.LineStart(line);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eol_pos; i++) {
char ch = styler[i];
int style = styler.StyleAt(i);
if (style == SCE_BAAN_WORD4)
return true;
else if (style == SCE_BAAN_WORD5)
return false;
else if (IsASpaceOrTab(ch))
continue;
else
break;
}
line++;
}
return false;
}
static bool IsDeclarationLine(Sci_Position line, LexAccessor &styler) {
Sci_Position pos = styler.LineStart(line);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eol_pos; i++) {
char ch = styler[i];
int style = styler.StyleAt(i);
if (style == SCE_BAAN_WORD) {
if (styler.Match(i, "table") || styler.Match(i, "extern") || styler.Match(i, "long")
|| styler.Match(i, "double") || styler.Match(i, "boolean") || styler.Match(i, "string")
|| styler.Match(i, "domain")) {
for (Sci_Position j = eol_pos; j > pos; j--) {
int styleFromEnd = styler.StyleAt(j);
if (styleFromEnd == SCE_BAAN_COMMENT)
continue;
else if (IsASpace(styler[j]))
continue;
else if (styler[j] != ',')
//Above conditions ensures, Declaration is not part of any function parameters.
return true;
else
return false;
}
}
else
return false;
}
else if (!IsASpaceOrTab(ch))
return false;
}
return false;
}
static bool IsInnerLevelFold(Sci_Position line, LexAccessor &styler) {
Sci_Position pos = styler.LineStart(line);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eol_pos; i++) {
char ch = styler[i];
int style = styler.StyleAt(i);
if (style == SCE_BAAN_WORD && (styler.Match(i, "else" ) || styler.Match(i, "case")
|| styler.Match(i, "default") || styler.Match(i, "selectdo") || styler.Match(i, "selecteos")
|| styler.Match(i, "selectempty") || styler.Match(i, "selecterror")))
return true;
else if (IsASpaceOrTab(ch))
continue;
else
return false;
}
return false;
}
static inline bool wordInArray(const std::string& value, std::string *array, int length)
{
for (int i = 0; i < length; i++)
{
if (value == array[i])
{
return true;
}
}
return false;
}
class WordListAbridged : public WordList {
public:
WordListAbridged() {
kwAbridged = false;
kwHasSection = false;
};
~WordListAbridged() {
Clear();
};
bool kwAbridged;
bool kwHasSection;
bool Contains(const char *s) {
return kwAbridged ? InListAbridged(s, '~') : InList(s);
};
};
}
class LexerBaan : public DefaultLexer {
WordListAbridged keywords;
WordListAbridged keywords2;
WordListAbridged keywords3;
WordListAbridged keywords4;
WordListAbridged keywords5;
WordListAbridged keywords6;
WordListAbridged keywords7;
WordListAbridged keywords8;
WordListAbridged keywords9;
OptionsBaan options;
OptionSetBaan osBaan;
public:
LexerBaan() : DefaultLexer("baan", SCLEX_BAAN) {
}
virtual ~LexerBaan() {
}
int SCI_METHOD Version() const override {
return lvRelease5;
}
void SCI_METHOD Release() override {
delete this;
}
const char * SCI_METHOD PropertyNames() override {
return osBaan.PropertyNames();
}
int SCI_METHOD PropertyType(const char * name) override {
return osBaan.PropertyType(name);
}
const char * SCI_METHOD DescribeProperty(const char * name) override {
return osBaan.DescribeProperty(name);
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
const char * SCI_METHOD PropertyGet(const char *key) override {
return osBaan.PropertyGet(key);
}
const char * SCI_METHOD DescribeWordListSets() override {
return osBaan.DescribeWordListSets();
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void * SCI_METHOD PrivateCall(int, void *) override {
return NULL;
}
static ILexer5 * LexerFactoryBaan() {
return new LexerBaan();
}
};
Sci_Position SCI_METHOD LexerBaan::PropertySet(const char *key, const char *val) {
if (osBaan.PropertySet(&options, key, val)) {
return 0;
}
return -1;
}
Sci_Position SCI_METHOD LexerBaan::WordListSet(int n, const char *wl) {
WordListAbridged *WordListAbridgedN = 0;
switch (n) {
case 0:
WordListAbridgedN = &keywords;
break;
case 1:
WordListAbridgedN = &keywords2;
break;
case 2:
WordListAbridgedN = &keywords3;
break;
case 3:
WordListAbridgedN = &keywords4;
break;
case 4:
WordListAbridgedN = &keywords5;
break;
case 5:
WordListAbridgedN = &keywords6;
break;
case 6:
WordListAbridgedN = &keywords7;
break;
case 7:
WordListAbridgedN = &keywords8;
break;
case 8:
WordListAbridgedN = &keywords9;
break;
}
Sci_Position firstModification = -1;
if (WordListAbridgedN) {
WordListAbridged wlNew;
wlNew.Set(wl);
if (*WordListAbridgedN != wlNew) {
WordListAbridgedN->Set(wl);
WordListAbridgedN->kwAbridged = strchr(wl, '~') != NULL;
WordListAbridgedN->kwHasSection = strchr(wl, ':') != NULL;
firstModification = 0;
}
}
return firstModification;
}
void SCI_METHOD LexerBaan::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
if (initStyle == SCE_BAAN_STRINGEOL) // Does not leak onto next line
initStyle = SCE_BAAN_DEFAULT;
int visibleChars = 0;
bool lineHasDomain = false;
bool lineHasFunction = false;
bool lineHasPreProc = false;
bool lineIgnoreString = false;
bool lineHasDefines = false;
bool numberIsHex = false;
char word[1000];
int wordlen = 0;
std::string preProcessorTags[13] = { "#context_off", "#context_on",
"#define", "#elif", "#else", "#endif",
"#ident", "#if", "#ifdef", "#ifndef",
"#include", "#pragma", "#undef" };
LexAccessor styler(pAccess);
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
// Determine if the current state should terminate.
switch (sc.state) {
case SCE_BAAN_OPERATOR:
sc.SetState(SCE_BAAN_DEFAULT);
break;
case SCE_BAAN_NUMBER:
if (IsASpaceOrTab(sc.ch) || sc.ch == '\r' || sc.ch == '\n' || IsAnOperator(sc.ch)) {
sc.SetState(SCE_BAAN_DEFAULT);
}
else if ((numberIsHex && !(MakeLowerCase(sc.ch) == 'x' || MakeLowerCase(sc.ch) == 'e' ||
IsADigit(sc.ch, 16) || sc.ch == '.' || sc.ch == '-' || sc.ch == '+')) ||
(!numberIsHex && !(MakeLowerCase(sc.ch) == 'e' || IsADigit(sc.ch)
|| sc.ch == '.' || sc.ch == '-' || sc.ch == '+'))) {
// check '-' for possible -10e-5. Add '+' as well.
numberIsHex = false;
sc.ChangeState(SCE_BAAN_IDENTIFIER);
sc.SetState(SCE_BAAN_DEFAULT);
}
break;
case SCE_BAAN_IDENTIFIER:
if (!IsAWordChar(sc.ch)) {
char s[1000];
char s1[1000];
sc.GetCurrentLowered(s, sizeof(s));
if (sc.ch == ':') {
memcpy(s1, s, sizeof(s));
s1[sc.LengthCurrent()] = sc.ch;
s1[sc.LengthCurrent() + 1] = '\0';
}
if ((keywords.kwHasSection && (sc.ch == ':')) ? keywords.Contains(s1) : keywords.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD);
if (0 == strcmp(s, "domain")) {
lineHasDomain = true;
}
else if (0 == strcmp(s, "function")) {
lineHasFunction = true;
}
}
else if (lineHasDomain) {
sc.ChangeState(SCE_BAAN_DOMDEF);
lineHasDomain = false;
}
else if (lineHasFunction) {
sc.ChangeState(SCE_BAAN_FUNCDEF);
lineHasFunction = false;
}
else if ((keywords2.kwHasSection && (sc.ch == ':')) ? keywords2.Contains(s1) : keywords2.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD2);
}
else if ((keywords3.kwHasSection && (sc.ch == ':')) ? keywords3.Contains(s1) : keywords3.Contains(s)) {
if (sc.ch == '(')
sc.ChangeState(SCE_BAAN_WORD3);
else
sc.ChangeState(SCE_BAAN_IDENTIFIER);
}
else if ((keywords4.kwHasSection && (sc.ch == ':')) ? keywords4.Contains(s1) : keywords4.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD4);
}
else if ((keywords5.kwHasSection && (sc.ch == ':')) ? keywords5.Contains(s1) : keywords5.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD5);
}
else if ((keywords6.kwHasSection && (sc.ch == ':')) ? keywords6.Contains(s1) : keywords6.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD6);
}
else if ((keywords7.kwHasSection && (sc.ch == ':')) ? keywords7.Contains(s1) : keywords7.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD7);
}
else if ((keywords8.kwHasSection && (sc.ch == ':')) ? keywords8.Contains(s1) : keywords8.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD8);
}
else if ((keywords9.kwHasSection && (sc.ch == ':')) ? keywords9.Contains(s1) : keywords9.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD9);
}
else if (lineHasPreProc) {
sc.ChangeState(SCE_BAAN_OBJECTDEF);
lineHasPreProc = false;
}
else if (lineHasDefines) {
sc.ChangeState(SCE_BAAN_DEFINEDEF);
lineHasDefines = false;
}
else {
int state = IsAnyOtherIdentifier(s, sc.LengthCurrent());
if (state > 0) {
sc.ChangeState(state);
}
}
sc.SetState(SCE_BAAN_DEFAULT);
}
break;
case SCE_BAAN_PREPROCESSOR:
if (options.baanStylingWithinPreprocessor) {
if (IsASpace(sc.ch) || IsAnOperator(sc.ch)) {
sc.SetState(SCE_BAAN_DEFAULT);
}
}
else {
if (sc.atLineEnd && (sc.chNext != '^')) {
sc.SetState(SCE_BAAN_DEFAULT);
}
}
break;
case SCE_BAAN_COMMENT:
if (sc.ch == '\r' || sc.ch == '\n') {
sc.SetState(SCE_BAAN_DEFAULT);
}
break;
case SCE_BAAN_COMMENTDOC:
if (sc.MatchIgnoreCase("enddllusage")) {
for (unsigned int i = 0; i < 10; i++) {
sc.Forward();
}
sc.ForwardSetState(SCE_BAAN_DEFAULT);
}
else if (sc.MatchIgnoreCase("endfunctionusage")) {
for (unsigned int i = 0; i < 15; i++) {
sc.Forward();
}
sc.ForwardSetState(SCE_BAAN_DEFAULT);
}
break;
case SCE_BAAN_STRING:
if (sc.ch == '\"') {
sc.ForwardSetState(SCE_BAAN_DEFAULT);
}
else if ((sc.atLineEnd) && (sc.chNext != '^')) {
sc.ChangeState(SCE_BAAN_STRINGEOL);
sc.ForwardSetState(SCE_BAAN_DEFAULT);
visibleChars = 0;
}
break;
}
// Determine if a new state should be entered.
if (sc.state == SCE_BAAN_DEFAULT) {
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))
|| ((sc.ch == '-' || sc.ch == '+') && (IsADigit(sc.chNext) || sc.chNext == '.'))
|| (MakeLowerCase(sc.ch) == 'e' && (IsADigit(sc.chNext) || sc.chNext == '+' || sc.chNext == '-'))) {
if ((sc.ch == '0' && MakeLowerCase(sc.chNext) == 'x') ||
((sc.ch == '-' || sc.ch == '+') && sc.chNext == '0' && MakeLowerCase(sc.GetRelativeCharacter(2)) == 'x')){
numberIsHex = true;
}
sc.SetState(SCE_BAAN_NUMBER);
}
else if (sc.MatchIgnoreCase("dllusage") || sc.MatchIgnoreCase("functionusage")) {
sc.SetState(SCE_BAAN_COMMENTDOC);
do {
sc.Forward();
} while ((!sc.atLineEnd) && sc.More());
}
else if (iswordstart(sc.ch)) {
sc.SetState(SCE_BAAN_IDENTIFIER);
}
else if (sc.Match('|')) {
sc.SetState(SCE_BAAN_COMMENT);
}
else if (sc.ch == '\"' && !(lineIgnoreString)) {
sc.SetState(SCE_BAAN_STRING);
}
else if (sc.ch == '#' && visibleChars == 0) {
// Preprocessor commands are alone on their line
sc.SetState(SCE_BAAN_PREPROCESSOR);
word[0] = '\0';
wordlen = 0;
while (sc.More() && !(IsASpace(sc.chNext) || IsAnOperator(sc.chNext))) {
sc.Forward();
wordlen++;
}
sc.GetCurrentLowered(word, sizeof(word));
if (!sc.atLineEnd) {
word[wordlen++] = sc.ch;
word[wordlen++] = '\0';
}
if (!wordInArray(word, preProcessorTags, 13))
// Colorise only preprocessor built in Baan.
sc.ChangeState(SCE_BAAN_IDENTIFIER);
if (strcmp(word, "#pragma") == 0 || strcmp(word, "#include") == 0) {
lineHasPreProc = true;
lineIgnoreString = true;
}
else if (strcmp(word, "#define") == 0 || strcmp(word, "#undef") == 0 ||
strcmp(word, "#ifdef") == 0 || strcmp(word, "#if") == 0 || strcmp(word, "#ifndef") == 0) {
lineHasDefines = true;
lineIgnoreString = false;
}
}
else if (IsAnOperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_BAAN_OPERATOR);
}
}
if (sc.atLineEnd) {
// Reset states to begining of colourise so no surprises
// if different sets of lines lexed.
visibleChars = 0;
lineHasDomain = false;
lineHasFunction = false;
lineHasPreProc = false;
lineIgnoreString = false;
lineHasDefines = false;
numberIsHex = false;
}
if (!IsASpace(sc.ch)) {
visibleChars++;
}
}
sc.Complete();
}
void SCI_METHOD LexerBaan::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
if (!options.fold)
return;
char word[100];
int wordlen = 0;
bool foldStart = true;
bool foldNextSelect = true;
bool afterFunctionSection = false;
bool beforeDeclarationSection = false;
int currLineStyle = 0;
int nextLineStyle = 0;
std::string startTags[6] = { "for", "if", "on", "repeat", "select", "while" };
std::string endTags[6] = { "endcase", "endfor", "endif", "endselect", "endwhile", "until" };
std::string selectCloseTags[5] = { "selectdo", "selecteos", "selectempty", "selecterror", "endselect" };
LexAccessor styler(pAccess);
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
// Backtrack to previous line in case need to fix its fold status
if (startPos > 0) {
if (lineCurrent > 0) {
lineCurrent--;
startPos = styler.LineStart(lineCurrent);
}
}
int levelPrev = SC_FOLDLEVELBASE;
if (lineCurrent > 0)
levelPrev = styler.LevelAt(lineCurrent - 1) >> 16;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
int style = initStyle;
int styleNext = styler.StyleAt(startPos);
for (Sci_PositionU i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
style = styleNext;
styleNext = styler.StyleAt(i + 1);
int stylePrev = (i) ? styler.StyleAt(i - 1) : SCE_BAAN_DEFAULT;
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
// Comment folding
if (options.foldComment && style == SCE_BAAN_COMMENTDOC) {
if (style != stylePrev) {
levelCurrent++;
}
else if (style != styleNext) {
levelCurrent--;
}
}
if (options.foldComment && atEOL && IsCommentLine(lineCurrent, styler)) {
if (!IsCommentLine(lineCurrent - 1, styler)
&& IsCommentLine(lineCurrent + 1, styler))
levelCurrent++;
else if (IsCommentLine(lineCurrent - 1, styler)
&& !IsCommentLine(lineCurrent + 1, styler))
levelCurrent--;
}
// PreProcessor Folding
if (options.foldPreprocessor) {
if (atEOL && IsPreProcLine(lineCurrent, styler)) {
if (!IsPreProcLine(lineCurrent - 1, styler)
&& IsPreProcLine(lineCurrent + 1, styler))
levelCurrent++;
else if (IsPreProcLine(lineCurrent - 1, styler)
&& !IsPreProcLine(lineCurrent + 1, styler))
levelCurrent--;
}
else if (style == SCE_BAAN_PREPROCESSOR) {
// folds #ifdef/#if/#ifndef - they are not part of the IsPreProcLine folding.
if (ch == '#') {
if (styler.Match(i, "#ifdef") || styler.Match(i, "#if") || styler.Match(i, "#ifndef")
|| styler.Match(i, "#context_on"))
levelCurrent++;
else if (styler.Match(i, "#endif") || styler.Match(i, "#context_off"))
levelCurrent--;
}
}
}
//Syntax Folding
if (options.baanFoldSyntaxBased && (style == SCE_BAAN_OPERATOR)) {
if (ch == '{' || ch == '(') {
levelCurrent++;
}
else if (ch == '}' || ch == ')') {
levelCurrent--;
}
}
//Keywords Folding
if (options.baanFoldKeywordsBased) {
if (atEOL && IsDeclarationLine(lineCurrent, styler)) {
if (!IsDeclarationLine(lineCurrent - 1, styler)
&& IsDeclarationLine(lineCurrent + 1, styler))
levelCurrent++;
else if (IsDeclarationLine(lineCurrent - 1, styler)
&& !IsDeclarationLine(lineCurrent + 1, styler))
levelCurrent--;
}
else if (style == SCE_BAAN_WORD) {
word[wordlen++] = static_cast<char>(MakeLowerCase(ch));
if (wordlen == 100) { // prevent overflow
word[0] = '\0';
wordlen = 1;
}
if (styleNext != SCE_BAAN_WORD) {
word[wordlen] = '\0';
wordlen = 0;
if (strcmp(word, "for") == 0) {
Sci_PositionU j = i + 1;
while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
j++;
}
if (styler.Match(j, "update")) {
// Means this is a "for update" used by Select which is already folded.
foldStart = false;
}
}
else if (strcmp(word, "on") == 0) {
Sci_PositionU j = i + 1;
while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
j++;
}
if (!styler.Match(j, "case")) {
// Means this is not a "on Case" statement... could be "on" used by index.
foldStart = false;
}
}
else if (strcmp(word, "select") == 0) {
if (foldNextSelect) {
// Next Selects are sub-clause till reach of selectCloseTags[] array.
foldNextSelect = false;
foldStart = true;
}
else {
foldNextSelect = false;
foldStart = false;
}
}
else if (wordInArray(word, selectCloseTags, 5)) {
// select clause ends, next select clause can be folded.
foldNextSelect = true;
foldStart = true;
}
else {
foldStart = true;
}
if (foldStart) {
if (wordInArray(word, startTags, 6)) {
levelCurrent++;
}
else if (wordInArray(word, endTags, 6)) {
levelCurrent--;
}
}
}
}
}
// Fold inner level of if/select/case statements
if (options.baanFoldInnerLevel && atEOL) {
bool currLineInnerLevel = IsInnerLevelFold(lineCurrent, styler);
bool nextLineInnerLevel = IsInnerLevelFold(lineCurrent + 1, styler);
if (currLineInnerLevel && currLineInnerLevel != nextLineInnerLevel) {
levelCurrent++;
}
else if (nextLineInnerLevel && nextLineInnerLevel != currLineInnerLevel) {
levelCurrent--;
}
}
// Section Foldings.
// One way of implementing Section Foldings, as there is no END markings of sections.
// first section ends on the previous line of next section.
// Re-written whole folding to accomodate this.
if (options.baanFoldSections && atEOL) {
currLineStyle = mainOrSubSectionLine(lineCurrent, styler);
nextLineStyle = mainOrSubSectionLine(lineCurrent + 1, styler);
if (currLineStyle != 0 && currLineStyle != nextLineStyle) {
if (levelCurrent < levelPrev)
--levelPrev;
for (Sci_Position j = styler.LineStart(lineCurrent); j < styler.LineStart(lineCurrent + 1) - 1; j++) {
if (IsASpaceOrTab(styler[j]))
continue;
else if (styler.StyleAt(j) == SCE_BAAN_WORD5) {
if (styler.Match(j, "functions:")) {
// Means functions: is the end of MainSections.
// Nothing to fold after this.
afterFunctionSection = true;
break;
}
else {
afterFunctionSection = false;
break;
}
}
else {
afterFunctionSection = false;
break;
}
}
if (!afterFunctionSection)
levelCurrent++;
}
else if (nextLineStyle != 0 && currLineStyle != nextLineStyle
&& (priorSectionIsSubSection(lineCurrent -1 ,styler)
|| !nextSectionIsSubSection(lineCurrent + 1, styler))) {
for (Sci_Position j = styler.LineStart(lineCurrent + 1); j < styler.LineStart(lineCurrent + 1 + 1) - 1; j++) {
if (IsASpaceOrTab(styler[j]))
continue;
else if (styler.StyleAt(j) == SCE_BAAN_WORD5) {
if (styler.Match(j, "declaration:")) {
// Means declaration: is the start of MainSections.
// Nothing to fold before this.
beforeDeclarationSection = true;
break;
}
else {
beforeDeclarationSection = false;
break;
}
}
else {
beforeDeclarationSection = false;
break;
}
}
if (!beforeDeclarationSection) {
levelCurrent--;
if (nextLineStyle == SCE_BAAN_WORD5 && priorSectionIsSubSection(lineCurrent-1, styler))
// next levelCurrent--; is to unfold previous subsection fold.
// On reaching the next main section, the previous main as well sub section ends.
levelCurrent--;
}
}
}
if (atEOL) {
int lev = levelPrev;
lev |= levelCurrent << 16;
if (visibleChars == 0 && options.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++;
}
int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}
LexerModule lmBaan(SCLEX_BAAN, LexerBaan::LexerFactoryBaan, "baan", baanWordLists);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,573 @@
// Scintilla source code edit control
/** @file LexBasic.cxx
** Lexer for BlitzBasic and PureBasic.
** Converted to lexer object and added further folding features/properties by "Udo Lechner" <dlchnr(at)gmx(dot)net>
**/
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
// This tries to be a unified Lexer/Folder for all the BlitzBasic/BlitzMax/PurBasic basics
// and derivatives. Once they diverge enough, might want to split it into multiple
// lexers for more code clearity.
//
// Mail me (elias <at> users <dot> sf <dot> net) for any bugs.
// Folding only works for simple things like functions or types.
// You may want to have a look at my ctags lexer as well, if you additionally to coloring
// and folding need to extract things like label tags in your editor.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include <string>
#include <string_view>
#include <map>
#include <functional>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "DefaultLexer.h"
using namespace Scintilla;
using namespace Lexilla;
/* Bits:
* 1 - whitespace
* 2 - operator
* 4 - identifier
* 8 - decimal digit
* 16 - hex digit
* 32 - bin digit
* 64 - letter
*/
static int character_classification[128] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 2,
60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2,
2, 84, 84, 84, 84, 84, 84, 68, 68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 2, 2, 2, 68,
2, 84, 84, 84, 84, 84, 84, 68, 68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 2, 2, 2, 0
};
static bool IsSpace(int c) {
return c < 128 && (character_classification[c] & 1);
}
static bool IsOperator(int c) {
return c < 128 && (character_classification[c] & 2);
}
static bool IsIdentifier(int c) {
return c < 128 && (character_classification[c] & 4);
}
static bool IsDigit(int c) {
return c < 128 && (character_classification[c] & 8);
}
static bool IsHexDigit(int c) {
return c < 128 && (character_classification[c] & 16);
}
static bool IsBinDigit(int c) {
return c < 128 && (character_classification[c] & 32);
}
static bool IsLetter(int c) {
return c < 128 && (character_classification[c] & 64);
}
static int LowerCase(int c)
{
if (c >= 'A' && c <= 'Z')
return 'a' + c - 'A';
return c;
}
static int CheckBlitzFoldPoint(char const *token, int &level) {
if (!strcmp(token, "function") ||
!strcmp(token, "type")) {
level |= SC_FOLDLEVELHEADERFLAG;
return 1;
}
if (!strcmp(token, "end function") ||
!strcmp(token, "end type")) {
return -1;
}
return 0;
}
static int CheckPureFoldPoint(char const *token, int &level) {
if (!strcmp(token, "procedure") ||
!strcmp(token, "enumeration") ||
!strcmp(token, "interface") ||
!strcmp(token, "structure")) {
level |= SC_FOLDLEVELHEADERFLAG;
return 1;
}
if (!strcmp(token, "endprocedure") ||
!strcmp(token, "endenumeration") ||
!strcmp(token, "endinterface") ||
!strcmp(token, "endstructure")) {
return -1;
}
return 0;
}
static int CheckFreeFoldPoint(char const *token, int &level) {
if (!strcmp(token, "function") ||
!strcmp(token, "sub") ||
!strcmp(token, "enum") ||
!strcmp(token, "type") ||
!strcmp(token, "union") ||
!strcmp(token, "property") ||
!strcmp(token, "destructor") ||
!strcmp(token, "constructor")) {
level |= SC_FOLDLEVELHEADERFLAG;
return 1;
}
if (!strcmp(token, "end function") ||
!strcmp(token, "end sub") ||
!strcmp(token, "end enum") ||
!strcmp(token, "end type") ||
!strcmp(token, "end union") ||
!strcmp(token, "end property") ||
!strcmp(token, "end destructor") ||
!strcmp(token, "end constructor")) {
return -1;
}
return 0;
}
// An individual named option for use in an OptionSet
// Options used for LexerBasic
struct OptionsBasic {
bool fold;
bool foldSyntaxBased;
bool foldCommentExplicit;
std::string foldExplicitStart;
std::string foldExplicitEnd;
bool foldExplicitAnywhere;
bool foldCompact;
OptionsBasic() {
fold = false;
foldSyntaxBased = true;
foldCommentExplicit = false;
foldExplicitStart = "";
foldExplicitEnd = "";
foldExplicitAnywhere = false;
foldCompact = true;
}
};
static const char * const blitzbasicWordListDesc[] = {
"BlitzBasic Keywords",
"user1",
"user2",
"user3",
0
};
static const char * const purebasicWordListDesc[] = {
"PureBasic Keywords",
"PureBasic PreProcessor Keywords",
"user defined 1",
"user defined 2",
0
};
static const char * const freebasicWordListDesc[] = {
"FreeBasic Keywords",
"FreeBasic PreProcessor Keywords",
"user defined 1",
"user defined 2",
0
};
struct OptionSetBasic : public OptionSet<OptionsBasic> {
OptionSetBasic(const char * const wordListDescriptions[]) {
DefineProperty("fold", &OptionsBasic::fold);
DefineProperty("fold.basic.syntax.based", &OptionsBasic::foldSyntaxBased,
"Set this property to 0 to disable syntax based folding.");
DefineProperty("fold.basic.comment.explicit", &OptionsBasic::foldCommentExplicit,
"This option enables folding explicit fold points when using the Basic lexer. "
"Explicit fold points allows adding extra folding by placing a ;{ (BB/PB) or '{ (FB) comment at the start "
"and a ;} (BB/PB) or '} (FB) at the end of a section that should be folded.");
DefineProperty("fold.basic.explicit.start", &OptionsBasic::foldExplicitStart,
"The string to use for explicit fold start points, replacing the standard ;{ (BB/PB) or '{ (FB).");
DefineProperty("fold.basic.explicit.end", &OptionsBasic::foldExplicitEnd,
"The string to use for explicit fold end points, replacing the standard ;} (BB/PB) or '} (FB).");
DefineProperty("fold.basic.explicit.anywhere", &OptionsBasic::foldExplicitAnywhere,
"Set this property to 1 to enable explicit fold points anywhere, not just in line comments.");
DefineProperty("fold.compact", &OptionsBasic::foldCompact);
DefineWordListSets(wordListDescriptions);
}
};
class LexerBasic : public DefaultLexer {
char comment_char;
int (*CheckFoldPoint)(char const *, int &);
WordList keywordlists[4];
OptionsBasic options;
OptionSetBasic osBasic;
public:
LexerBasic(const char *languageName_, int language_, char comment_char_,
int (*CheckFoldPoint_)(char const *, int &), const char * const wordListDescriptions[]) :
DefaultLexer(languageName_, language_),
comment_char(comment_char_),
CheckFoldPoint(CheckFoldPoint_),
osBasic(wordListDescriptions) {
}
virtual ~LexerBasic() {
}
void SCI_METHOD Release() override {
delete this;
}
int SCI_METHOD Version() const override {
return lvRelease5;
}
const char * SCI_METHOD PropertyNames() override {
return osBasic.PropertyNames();
}
int SCI_METHOD PropertyType(const char *name) override {
return osBasic.PropertyType(name);
}
const char * SCI_METHOD DescribeProperty(const char *name) override {
return osBasic.DescribeProperty(name);
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
const char * SCI_METHOD PropertyGet(const char *key) override {
return osBasic.PropertyGet(key);
}
const char * SCI_METHOD DescribeWordListSets() override {
return osBasic.DescribeWordListSets();
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void * SCI_METHOD PrivateCall(int, void *) override {
return 0;
}
static ILexer5 *LexerFactoryBlitzBasic() {
return new LexerBasic("blitzbasic", SCLEX_BLITZBASIC, ';', CheckBlitzFoldPoint, blitzbasicWordListDesc);
}
static ILexer5 *LexerFactoryPureBasic() {
return new LexerBasic("purebasic", SCLEX_PUREBASIC, ';', CheckPureFoldPoint, purebasicWordListDesc);
}
static ILexer5 *LexerFactoryFreeBasic() {
return new LexerBasic("freebasic", SCLEX_FREEBASIC, '\'', CheckFreeFoldPoint, freebasicWordListDesc );
}
};
Sci_Position SCI_METHOD LexerBasic::PropertySet(const char *key, const char *val) {
if (osBasic.PropertySet(&options, key, val)) {
return 0;
}
return -1;
}
Sci_Position SCI_METHOD LexerBasic::WordListSet(int n, const char *wl) {
WordList *wordListN = 0;
switch (n) {
case 0:
wordListN = &keywordlists[0];
break;
case 1:
wordListN = &keywordlists[1];
break;
case 2:
wordListN = &keywordlists[2];
break;
case 3:
wordListN = &keywordlists[3];
break;
}
Sci_Position firstModification = -1;
if (wordListN) {
WordList wlNew;
wlNew.Set(wl);
if (*wordListN != wlNew) {
wordListN->Set(wl);
firstModification = 0;
}
}
return firstModification;
}
void SCI_METHOD LexerBasic::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
LexAccessor styler(pAccess);
bool wasfirst = true, isfirst = true; // true if first token in a line
styler.StartAt(startPos);
int styleBeforeKeyword = SCE_B_DEFAULT;
StyleContext sc(startPos, length, initStyle, styler);
// Can't use sc.More() here else we miss the last character
for (; ; sc.Forward()) {
if (sc.state == SCE_B_IDENTIFIER) {
if (!IsIdentifier(sc.ch)) {
// Labels
if (wasfirst && sc.Match(':')) {
sc.ChangeState(SCE_B_LABEL);
sc.ForwardSetState(SCE_B_DEFAULT);
} else {
char s[100];
int kstates[4] = {
SCE_B_KEYWORD,
SCE_B_KEYWORD2,
SCE_B_KEYWORD3,
SCE_B_KEYWORD4,
};
sc.GetCurrentLowered(s, sizeof(s));
for (int i = 0; i < 4; i++) {
if (keywordlists[i].InList(s)) {
sc.ChangeState(kstates[i]);
}
}
// Types, must set them as operator else they will be
// matched as number/constant
if (sc.Match('.') || sc.Match('$') || sc.Match('%') ||
sc.Match('#')) {
sc.SetState(SCE_B_OPERATOR);
} else {
sc.SetState(SCE_B_DEFAULT);
}
}
}
} else if (sc.state == SCE_B_OPERATOR) {
if (!IsOperator(sc.ch) || sc.Match('#'))
sc.SetState(SCE_B_DEFAULT);
} else if (sc.state == SCE_B_LABEL) {
if (!IsIdentifier(sc.ch))
sc.SetState(SCE_B_DEFAULT);
} else if (sc.state == SCE_B_CONSTANT) {
if (!IsIdentifier(sc.ch))
sc.SetState(SCE_B_DEFAULT);
} else if (sc.state == SCE_B_NUMBER) {
if (!IsDigit(sc.ch))
sc.SetState(SCE_B_DEFAULT);
} else if (sc.state == SCE_B_HEXNUMBER) {
if (!IsHexDigit(sc.ch))
sc.SetState(SCE_B_DEFAULT);
} else if (sc.state == SCE_B_BINNUMBER) {
if (!IsBinDigit(sc.ch))
sc.SetState(SCE_B_DEFAULT);
} else if (sc.state == SCE_B_STRING) {
if (sc.ch == '"') {
sc.ForwardSetState(SCE_B_DEFAULT);
}
if (sc.atLineEnd) {
sc.ChangeState(SCE_B_ERROR);
sc.SetState(SCE_B_DEFAULT);
}
} else if (sc.state == SCE_B_COMMENT || sc.state == SCE_B_PREPROCESSOR) {
if (sc.atLineEnd) {
sc.SetState(SCE_B_DEFAULT);
}
} else if (sc.state == SCE_B_DOCLINE) {
if (sc.atLineEnd) {
sc.SetState(SCE_B_DEFAULT);
} else if (sc.ch == '\\' || sc.ch == '@') {
if (IsLetter(sc.chNext) && sc.chPrev != '\\') {
styleBeforeKeyword = sc.state;
sc.SetState(SCE_B_DOCKEYWORD);
};
}
} else if (sc.state == SCE_B_DOCKEYWORD) {
if (IsSpace(sc.ch)) {
sc.SetState(styleBeforeKeyword);
} else if (sc.atLineEnd && styleBeforeKeyword == SCE_B_DOCLINE) {
sc.SetState(SCE_B_DEFAULT);
}
} else if (sc.state == SCE_B_COMMENTBLOCK) {
if (sc.Match("\'/")) {
sc.Forward();
sc.ForwardSetState(SCE_B_DEFAULT);
}
} else if (sc.state == SCE_B_DOCBLOCK) {
if (sc.Match("\'/")) {
sc.Forward();
sc.ForwardSetState(SCE_B_DEFAULT);
} else if (sc.ch == '\\' || sc.ch == '@') {
if (IsLetter(sc.chNext) && sc.chPrev != '\\') {
styleBeforeKeyword = sc.state;
sc.SetState(SCE_B_DOCKEYWORD);
};
}
}
if (sc.atLineStart)
isfirst = true;
if (sc.state == SCE_B_DEFAULT || sc.state == SCE_B_ERROR) {
if (isfirst && sc.Match('.') && comment_char != '\'') {
sc.SetState(SCE_B_LABEL);
} else if (isfirst && sc.Match('#')) {
wasfirst = isfirst;
sc.SetState(SCE_B_IDENTIFIER);
} else if (sc.Match(comment_char)) {
// Hack to make deprecated QBASIC '$Include show
// up in freebasic with SCE_B_PREPROCESSOR.
if (comment_char == '\'' && sc.Match(comment_char, '$'))
sc.SetState(SCE_B_PREPROCESSOR);
else if (sc.Match("\'*") || sc.Match("\'!")) {
sc.SetState(SCE_B_DOCLINE);
} else {
sc.SetState(SCE_B_COMMENT);
}
} else if (sc.Match("/\'")) {
if (sc.Match("/\'*") || sc.Match("/\'!")) { // Support of gtk-doc/Doxygen doc. style
sc.SetState(SCE_B_DOCBLOCK);
} else {
sc.SetState(SCE_B_COMMENTBLOCK);
}
sc.Forward(); // Eat the ' so it isn't used for the end of the comment
} else if (sc.Match('"')) {
sc.SetState(SCE_B_STRING);
} else if (IsDigit(sc.ch)) {
sc.SetState(SCE_B_NUMBER);
} else if (sc.Match('$') || sc.Match("&h") || sc.Match("&H") || sc.Match("&o") || sc.Match("&O")) {
sc.SetState(SCE_B_HEXNUMBER);
} else if (sc.Match('%') || sc.Match("&b") || sc.Match("&B")) {
sc.SetState(SCE_B_BINNUMBER);
} else if (sc.Match('#')) {
sc.SetState(SCE_B_CONSTANT);
} else if (IsOperator(sc.ch)) {
sc.SetState(SCE_B_OPERATOR);
} else if (IsIdentifier(sc.ch)) {
wasfirst = isfirst;
sc.SetState(SCE_B_IDENTIFIER);
} else if (!IsSpace(sc.ch)) {
sc.SetState(SCE_B_ERROR);
}
}
if (!IsSpace(sc.ch))
isfirst = false;
if (!sc.More())
break;
}
sc.Complete();
}
void SCI_METHOD LexerBasic::Fold(Sci_PositionU startPos, Sci_Position length, int /* initStyle */, IDocument *pAccess) {
if (!options.fold)
return;
LexAccessor styler(pAccess);
Sci_Position line = styler.GetLine(startPos);
int level = styler.LevelAt(line);
int go = 0, done = 0;
Sci_Position endPos = startPos + length;
char word[256];
int wordlen = 0;
const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty();
int cNext = styler[startPos];
// Scan for tokens at the start of the line (they may include
// whitespace, for tokens like "End Function"
for (Sci_Position i = startPos; i < endPos; i++) {
int c = cNext;
cNext = styler.SafeGetCharAt(i + 1);
bool atEOL = (c == '\r' && cNext != '\n') || (c == '\n');
if (options.foldSyntaxBased && !done && !go) {
if (wordlen) { // are we scanning a token already?
word[wordlen] = static_cast<char>(LowerCase(c));
if (!IsIdentifier(c)) { // done with token
word[wordlen] = '\0';
go = CheckFoldPoint(word, level);
if (!go) {
// Treat any whitespace as single blank, for
// things like "End Function".
if (IsSpace(c) && IsIdentifier(word[wordlen - 1])) {
word[wordlen] = ' ';
if (wordlen < 255)
wordlen++;
}
else // done with this line
done = 1;
}
} else if (wordlen < 255) {
wordlen++;
}
} else { // start scanning at first non-whitespace character
if (!IsSpace(c)) {
if (IsIdentifier(c)) {
word[0] = static_cast<char>(LowerCase(c));
wordlen = 1;
} else // done with this line
done = 1;
}
}
}
if (options.foldCommentExplicit && ((styler.StyleAt(i) == SCE_B_COMMENT) || options.foldExplicitAnywhere)) {
if (userDefinedFoldMarkers) {
if (styler.Match(i, options.foldExplicitStart.c_str())) {
level |= SC_FOLDLEVELHEADERFLAG;
go = 1;
} else if (styler.Match(i, options.foldExplicitEnd.c_str())) {
go = -1;
}
} else {
if (c == comment_char) {
if (cNext == '{') {
level |= SC_FOLDLEVELHEADERFLAG;
go = 1;
} else if (cNext == '}') {
go = -1;
}
}
}
}
if (atEOL) { // line end
if (!done && wordlen == 0 && options.foldCompact) // line was only space
level |= SC_FOLDLEVELWHITEFLAG;
if (level != styler.LevelAt(line))
styler.SetLevel(line, level);
level += go;
line++;
// reset state
wordlen = 0;
level &= ~SC_FOLDLEVELHEADERFLAG;
level &= ~SC_FOLDLEVELWHITEFLAG;
go = 0;
done = 0;
}
}
}
LexerModule lmBlitzBasic(SCLEX_BLITZBASIC, LexerBasic::LexerFactoryBlitzBasic, "blitzbasic", blitzbasicWordListDesc);
LexerModule lmPureBasic(SCLEX_PUREBASIC, LexerBasic::LexerFactoryPureBasic, "purebasic", purebasicWordListDesc);
LexerModule lmFreeBasic(SCLEX_FREEBASIC, LexerBasic::LexerFactoryFreeBasic, "freebasic", freebasicWordListDesc);

View File

@ -0,0 +1,646 @@
// Scintilla source code edit control
/** @file LexBatch.cxx
** Lexer for batch files.
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cstdarg>
#include <string>
#include <string_view>
#include <initializer_list>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "InList.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
using namespace Lexilla;
namespace {
constexpr bool Is0To9(char ch) noexcept {
return (ch >= '0') && (ch <= '9');
}
bool IsAlphabetic(int ch) noexcept {
return IsASCII(ch) && isalpha(ch);
}
inline bool AtEOL(Accessor &styler, Sci_PositionU i) {
return (styler[i] == '\n') ||
((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n'));
}
// Tests for BATCH Operators
constexpr bool IsBOperator(char ch) noexcept {
return (ch == '=') || (ch == '+') || (ch == '>') || (ch == '<') ||
(ch == '|') || (ch == '?') || (ch == '*')||
(ch == '&') || (ch == '(') || (ch == ')');
}
// Tests for BATCH Separators
constexpr bool IsBSeparator(char ch) noexcept {
return (ch == '\\') || (ch == '.') || (ch == ';') ||
(ch == '\"') || (ch == '\'') || (ch == '/');
}
// Tests for escape character
constexpr bool IsEscaped(const char* wordStr, Sci_PositionU pos) noexcept {
bool isQoted=false;
while (pos>0){
pos--;
if (wordStr[pos]=='^')
isQoted=!isQoted;
else
break;
}
return isQoted;
}
constexpr bool IsQuotedBy(std::string_view svBuffer, char quote) noexcept {
bool CurrentStatus = false;
size_t pQuote = svBuffer.find(quote);
while (pQuote != std::string_view::npos) {
if (!IsEscaped(svBuffer.data(), pQuote)) {
CurrentStatus = !CurrentStatus;
}
pQuote = svBuffer.find(quote, pQuote + 1);
}
return CurrentStatus;
}
// Tests for quote character
constexpr bool textQuoted(const char *lineBuffer, Sci_PositionU endPos) noexcept {
const std::string_view svBuffer(lineBuffer, endPos);
return IsQuotedBy(svBuffer, '\"') || IsQuotedBy(svBuffer, '\'');
}
void ColouriseBatchDoc(
Sci_PositionU startPos,
Sci_Position length,
int /*initStyle*/,
WordList *keywordlists[],
Accessor &styler) {
// Always backtracks to the start of a line that is not a continuation
// of the previous line
if (startPos > 0) {
Sci_Position ln = styler.GetLine(startPos); // Current line number
while (startPos > 0) {
ln--;
if ((styler.SafeGetCharAt(startPos-3) == '^' && styler.SafeGetCharAt(startPos-2) == '\r' && styler.SafeGetCharAt(startPos-1) == '\n')
|| styler.SafeGetCharAt(startPos-2) == '^') { // handle '^' line continuation
// When the line continuation is found,
// set the Start Position to the Start of the previous line
length+=startPos-styler.LineStart(ln);
startPos=styler.LineStart(ln);
}
else
break;
}
}
char lineBuffer[1024] {};
styler.StartAt(startPos);
styler.StartSegment(startPos);
Sci_PositionU linePos = 0;
Sci_PositionU startLine = startPos;
bool continueProcessing = true; // Used to toggle Regular Keyword Checking
bool isNotAssigned=false; // Used to flag Assignment in Set operation
for (Sci_PositionU i = startPos; i < startPos + length; i++) {
lineBuffer[linePos++] = styler[i];
if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1) || (i==startPos + length-1)) {
// End of line (or of line buffer) (or End of Last Line) met, colourise it
lineBuffer[linePos] = '\0';
const Sci_PositionU lengthLine=linePos;
const Sci_PositionU endPos=i;
const WordList &keywords = *keywordlists[0]; // Internal Commands
const WordList &keywords2 = *keywordlists[1]; // External Commands (optional)
// CHOICE, ECHO, GOTO, PROMPT and SET have Default Text that may contain Regular Keywords
// Toggling Regular Keyword Checking off improves readability
// Other Regular Keywords and External Commands / Programs might also benefit from toggling
// Need a more robust algorithm to properly toggle Regular Keyword Checking
bool stopLineProcessing=false; // Used to stop line processing if Comment or Drive Change found
Sci_PositionU offset = 0; // Line Buffer Offset
// Skip initial spaces
while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {
offset++;
}
// Colorize Default Text
styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);
// Set External Command / Program Location
Sci_PositionU cmdLoc = offset;
// Check for Fake Label (Comment) or Real Label - return if found
if (lineBuffer[offset] == ':') {
if (lineBuffer[offset + 1] == ':') {
// Colorize Fake Label (Comment) - :: is similar to REM, see http://content.techweb.com/winmag/columns/explorer/2000/21.htm
styler.ColourTo(endPos, SCE_BAT_COMMENT);
} else {
// Colorize Real Label
// :[\t ]*[^\t &+:<>|]+
const char *startLabelName = lineBuffer + offset + 1;
const size_t whitespaceLength = strspn(startLabelName, "\t ");
// Set of label-terminating characters determined experimentally
const char *endLabel = strpbrk(startLabelName + whitespaceLength, "\t &+:<>|");
if (endLabel) {
styler.ColourTo(startLine + offset + endLabel - startLabelName, SCE_BAT_LABEL);
styler.ColourTo(endPos, SCE_BAT_AFTER_LABEL); // New style
} else {
styler.ColourTo(endPos, SCE_BAT_LABEL);
}
}
stopLineProcessing=true;
// Check for Drive Change (Drive Change is internal command) - return if found
} else if ((IsAlphabetic(lineBuffer[offset])) &&
(lineBuffer[offset + 1] == ':') &&
((isspacechar(lineBuffer[offset + 2])) ||
(((lineBuffer[offset + 2] == '\\')) &&
(isspacechar(lineBuffer[offset + 3]))))) {
// Colorize Regular Keyword
styler.ColourTo(endPos, SCE_BAT_WORD);
stopLineProcessing=true;
}
// Check for Hide Command (@ECHO OFF/ON)
if (lineBuffer[offset] == '@') {
styler.ColourTo(startLine + offset, SCE_BAT_HIDE);
offset++;
}
// Skip next spaces
while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {
offset++;
}
// Read remainder of line word-at-a-time or remainder-of-word-at-a-time
while (offset < lengthLine && !stopLineProcessing) {
if (offset > startLine) {
// Colorize Default Text
styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);
}
char wordBuffer[81]{}; // Word Buffer - large to catch long paths
// Copy word from Line Buffer into Word Buffer and convert to lower case
Sci_PositionU wbl = 0; // Word Buffer Length
for (; offset < lengthLine && wbl < 80 &&
!isspacechar(lineBuffer[offset]); wbl++, offset++) {
wordBuffer[wbl] = MakeLowerCase(lineBuffer[offset]);
}
wordBuffer[wbl] = '\0';
const std::string_view wordView(wordBuffer);
Sci_PositionU wbo = 0; // Word Buffer Offset - also Special Keyword Buffer Length
// Check for Comment - return if found
if (continueProcessing) {
if ((wordView == "rem") || (wordBuffer[0] == ':' && wordBuffer[1] == ':')) {
if ((offset == wbl) || !textQuoted(lineBuffer, offset - wbl)) {
styler.ColourTo(startLine + offset - wbl - 1, SCE_BAT_DEFAULT);
styler.ColourTo(endPos, SCE_BAT_COMMENT);
break;
}
}
}
// Check for Separator
if (IsBSeparator(wordBuffer[0])) {
// Check for External Command / Program
if ((cmdLoc == offset - wbl) &&
((wordBuffer[0] == ':') ||
(wordBuffer[0] == '\\') ||
(wordBuffer[0] == '.'))) {
// Reset Offset to re-process remainder of word
offset -= (wbl - 1);
// Colorize External Command / Program
if (!keywords2) {
styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);
} else if (keywords2.InList(wordBuffer)) {
styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);
} else {
styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);
}
// Reset External Command / Program Location
cmdLoc = offset;
} else {
// Reset Offset to re-process remainder of word
offset -= (wbl - 1);
// Colorize Default Text
styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);
}
// Check for Regular Keyword in list
} else if ((keywords.InList(wordBuffer)) &&
(continueProcessing)) {
// ECHO, GOTO, PROMPT and SET require no further Regular Keyword Checking
if (InList(wordView, {"echo", "goto", "prompt"})) {
continueProcessing = false;
}
// SET requires additional processing for the assignment operator
if (wordView == "set") {
continueProcessing = false;
isNotAssigned=true;
}
// Identify External Command / Program Location for ERRORLEVEL, and EXIST
if (InList(wordView, {"errorlevel", "exist"})) {
// Reset External Command / Program Location
cmdLoc = offset;
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
// Skip comparison
while ((cmdLoc < lengthLine) &&
(!isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
// Identify External Command / Program Location for CALL, DO, LOADHIGH and LH
} else if (InList(wordView, {"call", "do", "loadhigh", "lh"})) {
// Reset External Command / Program Location
cmdLoc = offset;
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
// Check if call is followed by a label
if ((lineBuffer[cmdLoc] == ':') &&
(wordView == "call")) {
continueProcessing = false;
}
}
// Colorize Regular keyword
styler.ColourTo(startLine + offset - 1, SCE_BAT_WORD);
// No need to Reset Offset
// Check for Special Keyword in list, External Command / Program, or Default Text
} else if ((wordBuffer[0] != '%') &&
(wordBuffer[0] != '!') &&
(!IsBOperator(wordBuffer[0])) &&
(continueProcessing)) {
// Check for Special Keyword
// Affected Commands are in Length range 2-6
// Good that ERRORLEVEL, EXIST, CALL, DO, LOADHIGH, and LH are unaffected
bool sKeywordFound = false; // Exit Special Keyword for-loop if found
for (Sci_PositionU keywordLength = 2; keywordLength < wbl && keywordLength < 7 && !sKeywordFound; keywordLength++) {
// Special Keywords are those that allow certain characters without whitespace after the command
// Examples are: cd. cd\ md. rd. dir| dir> echo: echo. path=
// Special Keyword Buffer used to determine if the first n characters is a Keyword
char sKeywordBuffer[10]{}; // Special Keyword Buffer
wbo = 0;
// Copy Keyword Length from Word Buffer into Special Keyword Buffer
for (; wbo < keywordLength; wbo++) {
sKeywordBuffer[wbo] = wordBuffer[wbo];
}
sKeywordBuffer[wbo] = '\0';
// Check for Special Keyword in list
if ((keywords.InList(sKeywordBuffer)) &&
((IsBOperator(wordBuffer[wbo])) ||
(IsBSeparator(wordBuffer[wbo])) ||
(wordBuffer[wbo] == ':' &&
(InList(sKeywordBuffer, {"call", "echo", "goto"}) )))) {
sKeywordFound = true;
// ECHO requires no further Regular Keyword Checking
if (std::string_view(sKeywordBuffer) == "echo") {
continueProcessing = false;
}
// Colorize Special Keyword as Regular Keyword
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_WORD);
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
}
}
// Check for External Command / Program or Default Text
if (!sKeywordFound) {
wbo = 0;
// Check for External Command / Program
if (cmdLoc == offset - wbl) {
// Read up to %, Operator or Separator
while ((wbo < wbl) &&
(((wordBuffer[wbo] != '%') &&
(wordBuffer[wbo] != '!') &&
(!IsBOperator(wordBuffer[wbo])) &&
(!IsBSeparator(wordBuffer[wbo]))))) {
wbo++;
}
// Reset External Command / Program Location
cmdLoc = offset - (wbl - wbo);
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
// CHOICE requires no further Regular Keyword Checking
if (wordView == "choice") {
continueProcessing = false;
}
// Check for START (and its switches) - What follows is External Command \ Program
if (wordView == "start") {
// Reset External Command / Program Location
cmdLoc = offset;
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
// Reset External Command / Program Location if command switch detected
if (lineBuffer[cmdLoc] == '/') {
// Skip command switch
while ((cmdLoc < lengthLine) &&
(!isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
}
}
// Colorize External Command / Program
if (!keywords2) {
styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);
} else if (keywords2.InList(wordBuffer)) {
styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);
} else {
styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);
}
// No need to Reset Offset
// Check for Default Text
} else {
// Read up to %, Operator or Separator
while ((wbo < wbl) &&
(((wordBuffer[wbo] != '%') &&
(wordBuffer[wbo] != '!') &&
(!IsBOperator(wordBuffer[wbo])) &&
(!IsBSeparator(wordBuffer[wbo]))))) {
wbo++;
}
// Colorize Default Text
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT);
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
}
}
// Check for Argument (%n), Environment Variable (%x...%) or Local Variable (%%a)
} else if (wordBuffer[0] == '%') {
// Colorize Default Text
styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT);
wbo++;
// Search to end of word for second % (can be a long path)
while ((wbo < wbl) &&
(wordBuffer[wbo] != '%')) {
wbo++;
}
// Check for Argument (%n) or (%*)
if (((Is0To9(wordBuffer[1])) || (wordBuffer[1] == '*')) &&
(wordBuffer[wbo] != '%')) {
// Check for External Command / Program
if (cmdLoc == offset - wbl) {
cmdLoc = offset - (wbl - 2);
}
// Colorize Argument
styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_IDENTIFIER);
// Reset Offset to re-process remainder of word
offset -= (wbl - 2);
// Check for Expanded Argument (%~...) / Variable (%%~...)
// Expanded Argument: %~[<path-operators>]<single digit>
// Expanded Variable: %%~[<path-operators>]<single identifier character>
// Path operators are exclusively alphabetic.
// Expanded arguments have a single digit at the end.
// Expanded variables have a single identifier character as variable name.
} else if (((wbl > 1) && (wordBuffer[1] == '~')) ||
((wbl > 2) && (wordBuffer[1] == '%') && (wordBuffer[2] == '~'))) {
// Check for External Command / Program
if (cmdLoc == offset - wbl) {
cmdLoc = offset - (wbl - wbo);
}
const bool isArgument = (wordBuffer[1] == '~');
if (isArgument) {
Sci_PositionU expansionStopOffset = 2;
bool isValid = false;
for (; expansionStopOffset < wbl; expansionStopOffset++) {
if (Is0To9(wordBuffer[expansionStopOffset])) {
expansionStopOffset++;
isValid = true;
wbo = expansionStopOffset;
// Colorize Expanded Argument
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);
break;
}
}
if (!isValid) {
// not a valid expanded argument or variable
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT);
}
// Expanded Variable
} else {
// start after ~
wbo = 3;
// Search to end of word for another % (can be a long path)
while ((wbo < wbl) &&
(wordBuffer[wbo] != '%') &&
(!IsBOperator(wordBuffer[wbo])) &&
(!IsBSeparator(wordBuffer[wbo]))) {
wbo++;
}
if (wbo > 3) {
// Colorize Expanded Variable
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);
} else {
// not a valid expanded argument or variable
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT);
}
}
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
// Check for Environment Variable (%x...%)
} else if ((wordBuffer[1] != '%') &&
(wordBuffer[wbo] == '%')) {
wbo++;
// Check for External Command / Program
if (cmdLoc == offset - wbl) {
cmdLoc = offset - (wbl - wbo);
}
// Colorize Environment Variable
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
// Check for Local Variable (%%a)
} else if (
(wbl > 2) &&
(wordBuffer[1] == '%') &&
(wordBuffer[2] != '%') &&
(!IsBOperator(wordBuffer[2])) &&
(!IsBSeparator(wordBuffer[2]))) {
// Check for External Command / Program
if (cmdLoc == offset - wbl) {
cmdLoc = offset - (wbl - 3);
}
// Colorize Local Variable
styler.ColourTo(startLine + offset - 1 - (wbl - 3), SCE_BAT_IDENTIFIER);
// Reset Offset to re-process remainder of word
offset -= (wbl - 3);
// escaped %
} else if (
(wbl > 1) &&
(wordBuffer[1] == '%')) {
// Reset Offset to re-process remainder of word
styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_DEFAULT);
offset -= (wbl - 2);
}
// Check for Environment Variable (!x...!)
} else if (wordBuffer[0] == '!') {
// Colorize Default Text
styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT);
wbo++;
// Search to end of word for second ! (can be a long path)
while ((wbo < wbl) &&
(wordBuffer[wbo] != '!')) {
wbo++;
}
if (wordBuffer[wbo] == '!') {
wbo++;
// Check for External Command / Program
if (cmdLoc == offset - wbl) {
cmdLoc = offset - (wbl - wbo);
}
// Colorize Environment Variable
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
}
// Check for Operator
} else if (IsBOperator(wordBuffer[0])) {
// Colorize Default Text
styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT);
// Check for Comparison Operator
if ((wordBuffer[0] == '=') && (wordBuffer[1] == '=')) {
// Identify External Command / Program Location for IF
cmdLoc = offset;
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
// Colorize Comparison Operator
if (continueProcessing)
styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_OPERATOR);
else
styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_DEFAULT);
// Reset Offset to re-process remainder of word
offset -= (wbl - 2);
// Check for Pipe Operator
} else if ((wordBuffer[0] == '|') &&
!(IsEscaped(lineBuffer,offset - wbl + wbo) || textQuoted(lineBuffer, offset - wbl) )) {
// Reset External Command / Program Location
cmdLoc = offset - wbl + 1;
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
// Colorize Pipe Operator
styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR);
// Reset Offset to re-process remainder of word
offset -= (wbl - 1);
continueProcessing = true;
// Check for Other Operator
} else {
// Check for Operators: >, |, &
if (((wordBuffer[0] == '>')||
(wordBuffer[0] == ')')||
(wordBuffer[0] == '(')||
(wordBuffer[0] == '&' )) &&
!(!continueProcessing && (IsEscaped(lineBuffer,offset - wbl + wbo)
|| textQuoted(lineBuffer, offset - wbl) ))){
// Turn Keyword and External Command / Program checking back on
continueProcessing = true;
isNotAssigned=false;
}
// Colorize Other Operators
// Do not Colorize Parenthesis, quoted text and escaped operators
if (((wordBuffer[0] != ')') && (wordBuffer[0] != '(')
&& !textQuoted(lineBuffer, offset - wbl) && !IsEscaped(lineBuffer,offset - wbl + wbo))
&& !((wordBuffer[0] == '=') && !isNotAssigned ))
styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR);
else
styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_DEFAULT);
// Reset Offset to re-process remainder of word
offset -= (wbl - 1);
if ((wordBuffer[0] == '=') && isNotAssigned ){
isNotAssigned=false;
}
}
// Check for Default Text
} else {
// Read up to %, Operator or Separator
while ((wbo < wbl) &&
((wordBuffer[wbo] != '%') &&
(wordBuffer[wbo] != '!') &&
(!IsBOperator(wordBuffer[wbo])) &&
(!IsBSeparator(wordBuffer[wbo])))) {
wbo++;
}
// Colorize Default Text
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT);
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
}
// Skip next spaces - nothing happens if Offset was Reset
while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {
offset++;
}
}
// Colorize Default Text for remainder of line - currently not lexed
styler.ColourTo(endPos, SCE_BAT_DEFAULT);
// handle line continuation for SET and ECHO commands except the last line
if (!continueProcessing && (i<startPos + length-1)) {
if (linePos==1 || (linePos==2 && lineBuffer[1]=='\r')) // empty line on Unix and Mac or on Windows
continueProcessing=true;
else {
Sci_PositionU lineContinuationPos;
if ((linePos>2) && lineBuffer[linePos-2]=='\r') // Windows EOL
lineContinuationPos=linePos-3;
else
lineContinuationPos=linePos-2; // Unix or Mac EOL
// Reset continueProcessing if line continuation was not found
if ((lineBuffer[lineContinuationPos]!='^')
|| IsEscaped(lineBuffer, lineContinuationPos)
|| textQuoted(lineBuffer, lineContinuationPos))
continueProcessing=true;
}
}
linePos = 0;
startLine = i + 1;
}
}
}
const char *const batchWordListDesc[] = {
"Internal Commands",
"External Commands",
nullptr
};
}
LexerModule lmBatch(SCLEX_BATCH, ColouriseBatchDoc, "batch", nullptr, batchWordListDesc);

View File

@ -0,0 +1,309 @@
// Copyright 2008-2010 Sergiu Dotenco. The License.txt file describes the
// conditions under which this software may be distributed.
/**
* @file LexBibTeX.cxx
* @brief General BibTeX coloring scheme.
* @author Sergiu Dotenco
* @date April 18, 2009
*/
#include <stdlib.h>
#include <string.h>
#include <cassert>
#include <cctype>
#include <string>
#include <string_view>
#include <algorithm>
#include <functional>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "PropSetSimple.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
using namespace Lexilla;
namespace {
bool IsAlphabetic(unsigned int ch)
{
return IsASCII(ch) && std::isalpha(ch) != 0;
}
bool IsAlphaNumeric(char ch)
{
return IsASCII(ch) && std::isalnum(ch);
}
bool EqualCaseInsensitive(const char* a, const char* b)
{
return CompareCaseInsensitive(a, b) == 0;
}
bool EntryWithoutKey(const char* name)
{
return EqualCaseInsensitive(name,"string");
}
char GetClosingBrace(char openbrace)
{
char result = openbrace;
switch (openbrace) {
case '(': result = ')'; break;
case '{': result = '}'; break;
}
return result;
}
bool IsEntryStart(char prev, char ch)
{
return prev != '\\' && ch == '@';
}
bool IsEntryStart(const StyleContext& sc)
{
return IsEntryStart(sc.chPrev, sc.ch);
}
void ColorizeBibTeX(Sci_PositionU start_pos, Sci_Position length, int /*init_style*/, WordList* keywordlists[], Accessor& styler)
{
WordList &EntryNames = *keywordlists[0];
bool fold_compact = styler.GetPropertyInt("fold.compact", 1) != 0;
std::string buffer;
buffer.reserve(25);
// We always colorize a section from the beginning, so let's
// search for the @ character which isn't escaped, i.e. \@
while (start_pos > 0 && !IsEntryStart(styler.SafeGetCharAt(start_pos - 1),
styler.SafeGetCharAt(start_pos))) {
--start_pos; ++length;
}
styler.StartAt(start_pos);
styler.StartSegment(start_pos);
Sci_Position current_line = styler.GetLine(start_pos);
int prev_level = styler.LevelAt(current_line) & SC_FOLDLEVELNUMBERMASK;
int current_level = prev_level;
int visible_chars = 0;
bool in_comment = false ;
StyleContext sc(start_pos, length, SCE_BIBTEX_DEFAULT, styler);
bool going = sc.More(); // needed because of a fuzzy end of file state
char closing_brace = 0;
bool collect_entry_name = false;
for (; going; sc.Forward()) {
if (!sc.More())
going = false; // we need to go one behind the end of text
if (in_comment) {
if (sc.atLineEnd) {
sc.SetState(SCE_BIBTEX_DEFAULT);
in_comment = false;
}
}
else {
// Found @entry
if (IsEntryStart(sc)) {
sc.SetState(SCE_BIBTEX_UNKNOWN_ENTRY);
sc.Forward();
++current_level;
buffer.clear();
collect_entry_name = true;
}
else if ((sc.state == SCE_BIBTEX_ENTRY || sc.state == SCE_BIBTEX_UNKNOWN_ENTRY)
&& (sc.ch == '{' || sc.ch == '(')) {
// Entry name colorization done
// Found either a { or a ( after entry's name, e.g. @entry(...) @entry{...}
// Closing counterpart needs to be stored.
closing_brace = GetClosingBrace(sc.ch);
sc.SetState(SCE_BIBTEX_DEFAULT); // Don't colorize { (
// @string doesn't have any key
if (EntryWithoutKey(buffer.c_str()))
sc.ForwardSetState(SCE_BIBTEX_PARAMETER);
else
sc.ForwardSetState(SCE_BIBTEX_KEY); // Key/label colorization
}
// Need to handle the case where entry's key is empty
// e.g. @book{,...}
if (sc.state == SCE_BIBTEX_KEY && sc.ch == ',') {
// Key/label colorization done
sc.SetState(SCE_BIBTEX_DEFAULT); // Don't colorize the ,
sc.ForwardSetState(SCE_BIBTEX_PARAMETER); // Parameter colorization
}
else if (sc.state == SCE_BIBTEX_PARAMETER && sc.ch == '=') {
sc.SetState(SCE_BIBTEX_DEFAULT); // Don't colorize the =
sc.ForwardSetState(SCE_BIBTEX_VALUE); // Parameter value colorization
Sci_Position start = sc.currentPos;
// We need to handle multiple situations:
// 1. name"one two {three}"
// 2. name={one {one two {two}} three}
// 3. year=2005
// Skip ", { until we encounter the first alphanumerical character
while (sc.More() && !(IsAlphaNumeric(sc.ch) || sc.ch == '"' || sc.ch == '{'))
sc.Forward();
if (sc.More()) {
// Store " or {
char ch = sc.ch;
// Not interested in alphanumerical characters
if (IsAlphaNumeric(ch))
ch = 0;
int skipped = 0;
if (ch) {
// Skip preceding " or { such as in name={{test}}.
// Remember how many characters have been skipped
// Make sure that empty values, i.e. "" are also handled correctly
while (sc.More() && (sc.ch == ch && (ch != '"' || skipped < 1))) {
sc.Forward();
++skipped;
}
}
// Closing counterpart for " is the same character
if (ch == '{')
ch = '}';
// We have reached the parameter value
// In case the open character was a alnum char, skip until , is found
// otherwise until skipped == 0
while (sc.More() && (skipped > 0 || (!ch && !(sc.ch == ',' || sc.ch == closing_brace)))) {
// Make sure the character isn't escaped
if (sc.chPrev != '\\') {
// Parameter value contains a { which is the 2nd case described above
if (sc.ch == '{')
++skipped; // Remember it
else if (sc.ch == '}')
--skipped;
else if (skipped == 1 && sc.ch == ch && ch == '"') // Don't ignore cases like {"o}
skipped = 0;
}
sc.Forward();
}
}
// Don't colorize the ,
sc.SetState(SCE_BIBTEX_DEFAULT);
// Skip until the , or entry's closing closing_brace is found
// since this parameter might be the last one
while (sc.More() && !(sc.ch == ',' || sc.ch == closing_brace))
sc.Forward();
int state = SCE_BIBTEX_PARAMETER; // The might be more parameters
// We've reached the closing closing_brace for the bib entry
// in case no " or {} has been used to enclose the value,
// as in 3rd case described above
if (sc.ch == closing_brace) {
--current_level;
// Make sure the text between entries is not colored
// using parameter's style
state = SCE_BIBTEX_DEFAULT;
}
Sci_Position end = sc.currentPos;
current_line = styler.GetLine(end);
// We have possibly skipped some lines, so the folding levels
// have to be adjusted separately
for (Sci_Position i = styler.GetLine(start); i <= styler.GetLine(end); ++i)
styler.SetLevel(i, prev_level);
sc.ForwardSetState(state);
}
if (sc.state == SCE_BIBTEX_PARAMETER && sc.ch == closing_brace) {
sc.SetState(SCE_BIBTEX_DEFAULT);
--current_level;
}
// Non escaped % found which represents a comment until the end of the line
if (sc.chPrev != '\\' && sc.ch == '%') {
in_comment = true;
sc.SetState(SCE_BIBTEX_COMMENT);
}
}
if (sc.state == SCE_BIBTEX_UNKNOWN_ENTRY || sc.state == SCE_BIBTEX_ENTRY) {
if (!IsAlphabetic(sc.ch) && collect_entry_name)
collect_entry_name = false;
if (collect_entry_name) {
buffer += static_cast<char>(tolower(sc.ch));
if (EntryNames.InList(buffer.c_str()))
sc.ChangeState(SCE_BIBTEX_ENTRY);
else
sc.ChangeState(SCE_BIBTEX_UNKNOWN_ENTRY);
}
}
if (sc.atLineEnd) {
int level = prev_level;
if (visible_chars == 0 && fold_compact)
level |= SC_FOLDLEVELWHITEFLAG;
if ((current_level > prev_level))
level |= SC_FOLDLEVELHEADERFLAG;
// else if (current_level < prev_level)
// level |= SC_FOLDLEVELBOXFOOTERFLAG; // Deprecated
if (level != styler.LevelAt(current_line)) {
styler.SetLevel(current_line, level);
}
++current_line;
prev_level = current_level;
visible_chars = 0;
}
if (!isspacechar(sc.ch))
++visible_chars;
}
sc.Complete();
// Fill in the real level of the next line, keeping the current flags as they will be filled in later
int flagsNext = styler.LevelAt(current_line) & ~SC_FOLDLEVELNUMBERMASK;
styler.SetLevel(current_line, prev_level | flagsNext);
}
}
static const char * const BibTeXWordLists[] = {
"Entry Names",
0,
};
LexerModule lmBibTeX(SCLEX_BIBTEX, ColorizeBibTeX, "bib", 0, BibTeXWordLists);
// Entry Names
// article, book, booklet, conference, inbook,
// incollection, inproceedings, manual, mastersthesis,
// misc, phdthesis, proceedings, techreport, unpublished,
// string, url

View File

@ -0,0 +1,234 @@
// SciTE - Scintilla based Text Editor
// LexBullant.cxx - lexer for Bullant
#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;
static int classifyWordBullant(Sci_PositionU start, Sci_PositionU end, WordList &keywords, Accessor &styler) {
char s[100];
s[0] = '\0';
for (Sci_PositionU i = 0; i < end - start + 1 && i < 30; i++) {
s[i] = static_cast<char>(tolower(styler[start + i]));
s[i + 1] = '\0';
}
int lev= 0;
char chAttr = SCE_C_IDENTIFIER;
if (isdigit(s[0]) || (s[0] == '.')){
chAttr = SCE_C_NUMBER;
}
else {
if (keywords.InList(s)) {
chAttr = SCE_C_WORD;
if (strcmp(s, "end") == 0)
lev = -1;
else if (strcmp(s, "method") == 0 ||
strcmp(s, "case") == 0 ||
strcmp(s, "class") == 0 ||
strcmp(s, "debug") == 0 ||
strcmp(s, "test") == 0 ||
strcmp(s, "if") == 0 ||
strcmp(s, "lock") == 0 ||
strcmp(s, "transaction") == 0 ||
strcmp(s, "trap") == 0 ||
strcmp(s, "until") == 0 ||
strcmp(s, "while") == 0)
lev = 1;
}
}
styler.ColourTo(end, chAttr);
return lev;
}
static void ColouriseBullantDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
WordList &keywords = *keywordlists[0];
styler.StartAt(startPos);
bool fold = styler.GetPropertyInt("fold") != 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
int state = initStyle;
if (state == SCE_C_STRINGEOL) // Does not leak onto next line
state = SCE_C_DEFAULT;
char chPrev = ' ';
char chNext = styler[startPos];
Sci_PositionU lengthDoc = startPos + length;
int visibleChars = 0;
styler.StartSegment(startPos);
int endFoundThisLine = 0;
for (Sci_PositionU i = startPos; i < lengthDoc; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
// Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
// Avoid triggering two times on Dos/Win
// End of line
endFoundThisLine = 0;
if (state == SCE_C_STRINGEOL) {
styler.ColourTo(i, state);
state = SCE_C_DEFAULT;
}
if (fold) {
int lev = levelPrev;
if (visibleChars == 0)
lev |= SC_FOLDLEVELWHITEFLAG;
if ((levelCurrent > levelPrev) && (visibleChars > 0))
lev |= SC_FOLDLEVELHEADERFLAG;
styler.SetLevel(lineCurrent, lev);
lineCurrent++;
levelPrev = levelCurrent;
}
visibleChars = 0;
/* int indentBlock = GetLineIndentation(lineCurrent);
if (blockChange==1){
lineCurrent++;
int pos=SetLineIndentation(lineCurrent, indentBlock + indentSize);
} else if (blockChange==-1) {
indentBlock -= indentSize;
if (indentBlock < 0)
indentBlock = 0;
SetLineIndentation(lineCurrent, indentBlock);
lineCurrent++;
}
blockChange=0;
*/ }
if (!(IsASCII(ch) && isspace(ch)))
visibleChars++;
if (styler.IsLeadByte(ch)) {
chNext = styler.SafeGetCharAt(i + 2);
chPrev = ' ';
i += 1;
continue;
}
if (state == SCE_C_DEFAULT) {
if (iswordstart(ch)) {
styler.ColourTo(i-1, state);
state = SCE_C_IDENTIFIER;
} else if (ch == '@' && chNext == 'o') {
if ((styler.SafeGetCharAt(i+2) =='f') && (styler.SafeGetCharAt(i+3) == 'f')) {
styler.ColourTo(i-1, state);
state = SCE_C_COMMENT;
}
} else if (ch == '#') {
styler.ColourTo(i-1, state);
state = SCE_C_COMMENTLINE;
} else if (ch == '\"') {
styler.ColourTo(i-1, state);
state = SCE_C_STRING;
} else if (ch == '\'') {
styler.ColourTo(i-1, state);
state = SCE_C_CHARACTER;
} else if (isoperator(ch)) {
styler.ColourTo(i-1, state);
styler.ColourTo(i, SCE_C_OPERATOR);
}
} else if (state == SCE_C_IDENTIFIER) {
if (!iswordchar(ch)) {
int levelChange = classifyWordBullant(styler.GetStartSegment(), i - 1, keywords, styler);
state = SCE_C_DEFAULT;
chNext = styler.SafeGetCharAt(i + 1);
if (ch == '#') {
state = SCE_C_COMMENTLINE;
} else if (ch == '\"') {
state = SCE_C_STRING;
} else if (ch == '\'') {
state = SCE_C_CHARACTER;
} else if (isoperator(ch)) {
styler.ColourTo(i, SCE_C_OPERATOR);
}
if (endFoundThisLine == 0)
levelCurrent+=levelChange;
if (levelChange == -1)
endFoundThisLine=1;
}
} else if (state == SCE_C_COMMENT) {
if (ch == '@' && chNext == 'o') {
if (styler.SafeGetCharAt(i+2) == 'n') {
styler.ColourTo(i+2, state);
state = SCE_C_DEFAULT;
i+=2;
}
}
} else if (state == SCE_C_COMMENTLINE) {
if (ch == '\r' || ch == '\n') {
endFoundThisLine = 0;
styler.ColourTo(i-1, state);
state = SCE_C_DEFAULT;
}
} else if (state == SCE_C_STRING) {
if (ch == '\\') {
if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
i++;
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
}
} else if (ch == '\"') {
styler.ColourTo(i, state);
state = SCE_C_DEFAULT;
} else if (chNext == '\r' || chNext == '\n') {
endFoundThisLine = 0;
styler.ColourTo(i-1, SCE_C_STRINGEOL);
state = SCE_C_STRINGEOL;
}
} else if (state == SCE_C_CHARACTER) {
if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) {
endFoundThisLine = 0;
styler.ColourTo(i-1, SCE_C_STRINGEOL);
state = SCE_C_STRINGEOL;
} else if (ch == '\\') {
if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
i++;
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
}
} else if (ch == '\'') {
styler.ColourTo(i, state);
state = SCE_C_DEFAULT;
}
}
chPrev = ch;
}
styler.ColourTo(lengthDoc - 1, state);
// Fill in the real level of the next line, keeping the current flags as they will be filled in later
if (fold) {
int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
//styler.SetLevel(lineCurrent, levelCurrent | flagsNext);
styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}
}
static const char * const bullantWordListDesc[] = {
"Keywords",
0
};
LexerModule lmBullant(SCLEX_BULLANT, ColouriseBullantDoc, "bullant", 0, bullantWordListDesc);

View File

@ -0,0 +1,410 @@
// Scintilla source code edit control
/** @file LexCIL.cxx
** Lexer for Common Intermediate Language
** Written by Jad Altahan (github.com/xv)
** CIL manual: https://www.ecma-international.org/publications/standards/Ecma-335.htm
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// 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 <map>
#include <algorithm>
#include <functional>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "StringCopy.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "DefaultLexer.h"
using namespace Scintilla;
using namespace Lexilla;
namespace {
// Use an unnamed namespace to protect the functions and classes from name conflicts
bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.');
}
bool IsOperator(const int ch) {
if ((ch < 0x80) && (isalnum(ch)))
return false;
if (strchr("!%&*+-/<=>@^|~()[]{}", ch)) {
return true;
}
return false;
}
constexpr bool IsStreamCommentStyle(const int style) noexcept {
return style == SCE_CIL_COMMENT;
}
struct OptionsCIL {
bool fold;
bool foldComment;
bool foldCommentMultiline;
bool foldCompact;
OptionsCIL() {
fold = true;
foldComment = false;
foldCommentMultiline = true;
foldCompact = true;
}
};
static const char *const cilWordListDesc[] = {
"Primary CIL keywords",
"Metadata",
"Opcode instructions",
0
};
struct OptionSetCIL : public OptionSet<OptionsCIL> {
OptionSetCIL() {
DefineProperty("fold", &OptionsCIL::fold);
DefineProperty("fold.comment", &OptionsCIL::foldComment);
DefineProperty("fold.cil.comment.multiline", &OptionsCIL::foldCommentMultiline,
"Set this property to 0 to disable folding multi-line comments when fold.comment=1.");
DefineProperty("fold.compact", &OptionsCIL::foldCompact);
DefineWordListSets(cilWordListDesc);
}
};
LexicalClass lexicalClasses[] = {
// Lexer CIL SCLEX_CIL SCE_CIL_:
0, "SCE_CIL_DEFAULT", "default", "White space",
1, "SCE_CIL_COMMENT", "comment", "Multi-line comment",
2, "SCE_CIL_COMMENTLINE", "comment line", "Line comment",
3, "SCE_CIL_WORD", "keyword", "Keyword 1",
4, "SCE_CIL_WORD2", "keyword", "Keyword 2",
5, "SCE_CIL_WORD3", "keyword", "Keyword 3",
6, "SCE_CIL_STRING", "literal string", "Double quoted string",
7, "SCE_CIL_LABEL", "label", "Code label",
8, "SCE_CIL_OPERATOR", "operator", "Operators",
9, "SCE_CIL_STRINGEOL", "error literal string", "String is not closed",
10, "SCE_CIL_IDENTIFIER", "identifier", "Identifiers",
};
}
class LexerCIL : public DefaultLexer {
WordList keywords, keywords2, keywords3;
OptionsCIL options;
OptionSetCIL osCIL;
public:
LexerCIL() : DefaultLexer("cil", SCLEX_CIL, lexicalClasses, ELEMENTS(lexicalClasses)) { }
virtual ~LexerCIL() { }
void SCI_METHOD Release() override {
delete this;
}
int SCI_METHOD Version() const override {
return lvRelease5;
}
const char * SCI_METHOD PropertyNames() override {
return osCIL.PropertyNames();
}
int SCI_METHOD PropertyType(const char *name) override {
return osCIL.PropertyType(name);
}
const char * SCI_METHOD DescribeProperty(const char *name) override {
return osCIL.DescribeProperty(name);
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
const char * SCI_METHOD PropertyGet(const char* key) override {
return osCIL.PropertyGet(key);
}
const char * SCI_METHOD DescribeWordListSets() override {
return osCIL.DescribeWordListSets();
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void * SCI_METHOD PrivateCall(int, void *) override {
return 0;
}
int SCI_METHOD LineEndTypesSupported() override {
return SC_LINE_END_TYPE_UNICODE;
}
int SCI_METHOD PrimaryStyleFromStyle(int style) override {
return style;
}
static ILexer5 *LexerFactoryCIL() {
return new LexerCIL();
}
};
Sci_Position SCI_METHOD LexerCIL::PropertySet(const char *key, const char *val) {
if (osCIL.PropertySet(&options, key, val)) {
return 0;
}
return -1;
}
Sci_Position SCI_METHOD LexerCIL::WordListSet(int n, const char *wl) {
WordList *wordListN = 0;
switch (n) {
case 0:
wordListN = &keywords;
break;
case 1:
wordListN = &keywords2;
break;
case 2:
wordListN = &keywords3;
break;
}
Sci_Position firstModification = -1;
if (wordListN) {
WordList wlNew;
wlNew.Set(wl);
if (*wordListN != wlNew) {
wordListN->Set(wl);
firstModification = 0;
}
}
return firstModification;
}
void SCI_METHOD LexerCIL::Lex(Sci_PositionU startPos, Sci_Position length,
int initStyle, IDocument *pAccess) {
if (initStyle == SCE_CIL_STRINGEOL) {
initStyle = SCE_CIL_DEFAULT;
}
Accessor styler(pAccess, NULL);
StyleContext sc(startPos, length, initStyle, styler);
bool identAtLineStart = false, // Checks if an identifier is at line start (ignoring spaces)
canStyleLabels = false; // Checks if conditions are met to style SCE_CIL_LABEL
for (; sc.More(); sc.Forward()) {
if (sc.atLineStart) {
if (sc.state == SCE_CIL_STRING) {
sc.SetState(SCE_CIL_STRING);
}
identAtLineStart = true;
}
// Handle string line continuation
if (sc.ch == '\\' && (sc.chNext == '\n' || sc.chNext == '\r') &&
(sc.state == SCE_CIL_STRING)) {
sc.Forward();
if (sc.ch == '\r' && sc.chNext == '\n') {
sc.Forward();
}
continue;
}
switch (sc.state) {
case SCE_CIL_OPERATOR:
sc.SetState(SCE_CIL_DEFAULT);
break;
case SCE_CIL_IDENTIFIER:
if (!IsAWordChar(sc.ch)) {
if (canStyleLabels && (sc.ch == ':' && sc.chNext != ':')) {
sc.ChangeState(SCE_CIL_LABEL);
sc.ForwardSetState(SCE_CIL_DEFAULT);
} else {
char kwSize[100];
sc.GetCurrent(kwSize, sizeof(kwSize));
int style = SCE_CIL_IDENTIFIER;
if (keywords.InList(kwSize)) {
style = SCE_CIL_WORD;
} else if (keywords2.InList(kwSize)) {
style = SCE_CIL_WORD2;
} else if (keywords3.InList(kwSize)) {
style = SCE_CIL_WORD3;
}
sc.ChangeState(style);
sc.SetState(SCE_CIL_DEFAULT);
}
}
break;
case SCE_CIL_COMMENT:
if (sc.Match('*', '/')) {
sc.Forward();
sc.ForwardSetState(SCE_CIL_DEFAULT);
}
break;
case SCE_CIL_COMMENTLINE:
if (sc.atLineStart) {
sc.SetState(SCE_CIL_DEFAULT);
}
break;
case SCE_CIL_STRING:
if (sc.ch == '\\') {
if (sc.chNext == '"' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '"') {
sc.ForwardSetState(SCE_CIL_DEFAULT);
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_CIL_STRINGEOL);
sc.ForwardSetState(SCE_CIL_DEFAULT);
}
break;
}
if (sc.state == SCE_CIL_DEFAULT) {
// String
if (sc.ch == '"') {
sc.SetState(SCE_CIL_STRING);
}
// Keyword
else if (IsAWordChar(sc.ch)) {
// Allow setting SCE_CIL_LABEL style only if the label is the
// first token in the line and does not start with a dot or a digit
canStyleLabels = identAtLineStart && !(sc.ch == '.' || IsADigit(sc.ch));
sc.SetState(SCE_CIL_IDENTIFIER);
}
// Multi-line comment
else if (sc.Match('/', '*')) {
sc.SetState(SCE_CIL_COMMENT);
sc.Forward();
}
// Line comment
else if (sc.Match('/', '/')) {
sc.SetState(SCE_CIL_COMMENTLINE);
}
// Operators
else if (IsOperator(sc.ch)) {
sc.SetState(SCE_CIL_OPERATOR);
}
}
if (!IsASpace(sc.ch)) {
identAtLineStart = false;
}
}
sc.Complete();
}
void SCI_METHOD LexerCIL::Fold(Sci_PositionU startPos, Sci_Position length,
int initStyle, IDocument *pAccess) {
if (!options.fold) {
return;
}
LexAccessor styler(pAccess);
const Sci_PositionU endPos = startPos + length;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelCurrent = SC_FOLDLEVELBASE;
if (lineCurrent > 0)
levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16;
int style = initStyle;
int styleNext = styler.StyleAt(startPos);
int levelNext = levelCurrent;
int visibleChars = 0;
char chNext = styler[startPos];
for (Sci_PositionU i = startPos; i < endPos; i++) {
const char ch = chNext;
int stylePrev = style;
chNext = styler.SafeGetCharAt(i + 1);
style = styleNext;
styleNext = styler.StyleAt(i + 1);
const bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
if (options.foldComment &&
options.foldCommentMultiline && IsStreamCommentStyle(style)) {
if (!IsStreamCommentStyle(stylePrev)) {
levelNext++;
} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
levelNext--;
}
}
if (style == SCE_CIL_OPERATOR) {
if (ch == '{') {
levelNext++;
} else if (ch == '}') {
levelNext--;
}
}
if (!IsASpace(ch)) {
visibleChars++;
}
if (atEOL || (i == endPos - 1)) {
int lev = levelCurrent | levelNext << 16;
if (visibleChars == 0 && options.foldCompact)
lev |= SC_FOLDLEVELWHITEFLAG;
if (levelCurrent < levelNext)
lev |= SC_FOLDLEVELHEADERFLAG;
if (lev != styler.LevelAt(lineCurrent)) {
styler.SetLevel(lineCurrent, lev);
}
lineCurrent++;
levelCurrent = levelNext;
if (options.foldCompact &&
i == static_cast<Sci_PositionU>(styler.Length() - 1)) {
styler.SetLevel(lineCurrent, lev | SC_FOLDLEVELWHITEFLAG);
}
visibleChars = 0;
}
}
}
LexerModule lmCIL(SCLEX_CIL, LexerCIL::LexerFactoryCIL, "cil", cilWordListDesc);

View File

@ -0,0 +1,683 @@
// Scintilla source code edit control
/** @file LexCLW.cxx
** Lexer for Clarion.
** 2004/12/17 Updated Lexer
**/
// Copyright 2003-2004 by Ron Schofield <ron@schofieldcomputer.com>
// 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;
// Is an end of line character
inline bool IsEOL(const int ch) {
return(ch == '\n');
}
// Convert character to uppercase
static char CharacterUpper(char chChar) {
if (chChar < 'a' || chChar > 'z') {
return(chChar);
}
else {
return(static_cast<char>(chChar - 'a' + 'A'));
}
}
// Convert string to uppercase
static void StringUpper(char *szString) {
while (*szString) {
*szString = CharacterUpper(*szString);
szString++;
}
}
// Is a label start character
inline bool IsALabelStart(const int iChar) {
return(isalpha(iChar) || iChar == '_');
}
// Is a label character
inline bool IsALabelCharacter(const int iChar) {
return(isalnum(iChar) || iChar == '_' || iChar == ':');
}
// Is the character is a ! and the the next character is not a !
inline bool IsACommentStart(const int iChar) {
return(iChar == '!');
}
// Is the character a Clarion hex character (ABCDEF)
inline bool IsAHexCharacter(const int iChar, bool bCaseSensitive) {
// Case insensitive.
if (!bCaseSensitive) {
if (strchr("ABCDEFabcdef", iChar) != NULL) {
return(true);
}
}
// Case sensitive
else {
if (strchr("ABCDEF", iChar) != NULL) {
return(true);
}
}
return(false);
}
// Is the character a Clarion base character (B=Binary, O=Octal, H=Hex)
inline bool IsANumericBaseCharacter(const int iChar, bool bCaseSensitive) {
// Case insensitive.
if (!bCaseSensitive) {
// If character is a numeric base character
if (strchr("BOHboh", iChar) != NULL) {
return(true);
}
}
// Case sensitive
else {
// If character is a numeric base character
if (strchr("BOH", iChar) != NULL) {
return(true);
}
}
return(false);
}
// Set the correct numeric constant state
inline bool SetNumericConstantState(StyleContext &scDoc) {
int iPoints = 0; // Point counter
char cNumericString[512]; // Numeric string buffer
// Buffer the current numberic string
scDoc.GetCurrent(cNumericString, sizeof(cNumericString));
// Loop through the string until end of string (NULL termination)
for (int iIndex = 0; cNumericString[iIndex] != '\0'; iIndex++) {
// Depending on the character
switch (cNumericString[iIndex]) {
// Is a . (point)
case '.' :
// Increment point counter
iPoints++;
break;
default :
break;
}
}
// If points found (can be more than one for improper formatted number
if (iPoints > 0) {
return(true);
}
// Else no points found
else {
return(false);
}
}
// Get the next word in uppercase from the current position (keyword lookahead)
inline bool GetNextWordUpper(Accessor &styler, Sci_PositionU uiStartPos, Sci_Position iLength, char *cWord) {
Sci_PositionU iIndex = 0; // Buffer Index
// Loop through the remaining string from the current position
for (Sci_Position iOffset = uiStartPos; iOffset < iLength; iOffset++) {
// Get the character from the buffer using the offset
char cCharacter = styler[iOffset];
if (IsEOL(cCharacter)) {
break;
}
// If the character is alphabet character
if (isalpha(cCharacter)) {
// Add UPPERCASE character to the word buffer
cWord[iIndex++] = CharacterUpper(cCharacter);
}
}
// Add null termination
cWord[iIndex] = '\0';
// If no word was found
if (iIndex == 0) {
// Return failure
return(false);
}
// Else word was found
else {
// Return success
return(true);
}
}
// Clarion Language Colouring Procedure
static void ColouriseClarionDoc(Sci_PositionU uiStartPos, Sci_Position iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler, bool bCaseSensitive) {
int iParenthesesLevel = 0; // Parenthese Level
int iColumn1Label = false; // Label starts in Column 1
WordList &wlClarionKeywords = *wlKeywords[0]; // Clarion Keywords
WordList &wlCompilerDirectives = *wlKeywords[1]; // Compiler Directives
WordList &wlRuntimeExpressions = *wlKeywords[2]; // Runtime Expressions
WordList &wlBuiltInProcsFuncs = *wlKeywords[3]; // Builtin Procedures and Functions
WordList &wlStructsDataTypes = *wlKeywords[4]; // Structures and Data Types
WordList &wlAttributes = *wlKeywords[5]; // Procedure Attributes
WordList &wlStandardEquates = *wlKeywords[6]; // Standard Equates
WordList &wlLabelReservedWords = *wlKeywords[7]; // Clarion Reserved Keywords (Labels)
WordList &wlProcLabelReservedWords = *wlKeywords[8]; // Clarion Reserved Keywords (Procedure Labels)
const char wlProcReservedKeywordList[] =
"PROCEDURE FUNCTION";
WordList wlProcReservedKeywords;
wlProcReservedKeywords.Set(wlProcReservedKeywordList);
const char wlCompilerKeywordList[] =
"COMPILE OMIT";
WordList wlCompilerKeywords;
wlCompilerKeywords.Set(wlCompilerKeywordList);
const char wlLegacyStatementsList[] =
"BOF EOF FUNCTION POINTER SHARE";
WordList wlLegacyStatements;
wlLegacyStatements.Set(wlLegacyStatementsList);
StyleContext scDoc(uiStartPos, iLength, iInitStyle, accStyler);
// lex source code
for (; scDoc.More(); scDoc.Forward())
{
//
// Determine if the current state should terminate.
//
// Label State Handling
if (scDoc.state == SCE_CLW_LABEL) {
// If the character is not a valid label
if (!IsALabelCharacter(scDoc.ch)) {
// If the character is a . (dot syntax)
if (scDoc.ch == '.') {
// Turn off column 1 label flag as label now cannot be reserved work
iColumn1Label = false;
// Uncolour the . (dot) to default state, move forward one character,
// and change back to the label state.
scDoc.SetState(SCE_CLW_DEFAULT);
scDoc.Forward();
scDoc.SetState(SCE_CLW_LABEL);
}
// Else check label
else {
char cLabel[512]; // Label buffer
// Buffer the current label string
scDoc.GetCurrent(cLabel,sizeof(cLabel));
// If case insensitive, convert string to UPPERCASE to match passed keywords.
if (!bCaseSensitive) {
StringUpper(cLabel);
}
// Else if UPPERCASE label string is in the Clarion compiler keyword list
if (wlCompilerKeywords.InList(cLabel) && iColumn1Label){
// change the label to error state
scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE);
}
// Else if UPPERCASE label string is in the Clarion reserved keyword list
else if (wlLabelReservedWords.InList(cLabel) && iColumn1Label){
// change the label to error state
scDoc.ChangeState(SCE_CLW_ERROR);
}
// Else if UPPERCASE label string is
else if (wlProcLabelReservedWords.InList(cLabel) && iColumn1Label) {
char cWord[512]; // Word buffer
// Get the next word from the current position
if (GetNextWordUpper(accStyler,scDoc.currentPos,uiStartPos+iLength,cWord)) {
// If the next word is a procedure reserved word
if (wlProcReservedKeywords.InList(cWord)) {
// Change the label to error state
scDoc.ChangeState(SCE_CLW_ERROR);
}
}
}
// Else if label string is in the compiler directive keyword list
else if (wlCompilerDirectives.InList(cLabel)) {
// change the state to compiler directive state
scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE);
}
// Terminate the label state and set to default state
scDoc.SetState(SCE_CLW_DEFAULT);
}
}
}
// Keyword State Handling
else if (scDoc.state == SCE_CLW_KEYWORD) {
// If character is : (colon)
if (scDoc.ch == ':') {
char cEquate[512]; // Equate buffer
// Move forward to include : (colon) in buffer
scDoc.Forward();
// Buffer the equate string
scDoc.GetCurrent(cEquate,sizeof(cEquate));
// If case insensitive, convert string to UPPERCASE to match passed keywords.
if (!bCaseSensitive) {
StringUpper(cEquate);
}
// If statement string is in the equate list
if (wlStandardEquates.InList(cEquate)) {
// Change to equate state
scDoc.ChangeState(SCE_CLW_STANDARD_EQUATE);
}
}
// If the character is not a valid label character
else if (!IsALabelCharacter(scDoc.ch)) {
char cStatement[512]; // Statement buffer
// Buffer the statement string
scDoc.GetCurrent(cStatement,sizeof(cStatement));
// If case insensitive, convert string to UPPERCASE to match passed keywords.
if (!bCaseSensitive) {
StringUpper(cStatement);
}
// If statement string is in the Clarion keyword list
if (wlClarionKeywords.InList(cStatement)) {
// Change the statement string to the Clarion keyword state
scDoc.ChangeState(SCE_CLW_KEYWORD);
}
// Else if statement string is in the compiler directive keyword list
else if (wlCompilerDirectives.InList(cStatement)) {
// Change the statement string to the compiler directive state
scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE);
}
// Else if statement string is in the runtime expressions keyword list
else if (wlRuntimeExpressions.InList(cStatement)) {
// Change the statement string to the runtime expressions state
scDoc.ChangeState(SCE_CLW_RUNTIME_EXPRESSIONS);
}
// Else if statement string is in the builtin procedures and functions keyword list
else if (wlBuiltInProcsFuncs.InList(cStatement)) {
// Change the statement string to the builtin procedures and functions state
scDoc.ChangeState(SCE_CLW_BUILTIN_PROCEDURES_FUNCTION);
}
// Else if statement string is in the tructures and data types keyword list
else if (wlStructsDataTypes.InList(cStatement)) {
// Change the statement string to the structures and data types state
scDoc.ChangeState(SCE_CLW_STRUCTURE_DATA_TYPE);
}
// Else if statement string is in the procedure attribute keyword list
else if (wlAttributes.InList(cStatement)) {
// Change the statement string to the procedure attribute state
scDoc.ChangeState(SCE_CLW_ATTRIBUTE);
}
// Else if statement string is in the standard equate keyword list
else if (wlStandardEquates.InList(cStatement)) {
// Change the statement string to the standard equate state
scDoc.ChangeState(SCE_CLW_STANDARD_EQUATE);
}
// Else if statement string is in the deprecated or legacy keyword list
else if (wlLegacyStatements.InList(cStatement)) {
// Change the statement string to the standard equate state
scDoc.ChangeState(SCE_CLW_DEPRECATED);
}
// Else the statement string doesn't match any work list
else {
// Change the statement string to the default state
scDoc.ChangeState(SCE_CLW_DEFAULT);
}
// Terminate the keyword state and set to default state
scDoc.SetState(SCE_CLW_DEFAULT);
}
}
// String State Handling
else if (scDoc.state == SCE_CLW_STRING) {
// If the character is an ' (single quote)
if (scDoc.ch == '\'') {
// Set the state to default and move forward colouring
// the ' (single quote) as default state
// terminating the string state
scDoc.SetState(SCE_CLW_DEFAULT);
scDoc.Forward();
}
// If the next character is an ' (single quote)
if (scDoc.chNext == '\'') {
// Move forward one character and set to default state
// colouring the next ' (single quote) as default state
// terminating the string state
scDoc.ForwardSetState(SCE_CLW_DEFAULT);
scDoc.Forward();
}
}
// Picture String State Handling
else if (scDoc.state == SCE_CLW_PICTURE_STRING) {
// If the character is an ( (open parenthese)
if (scDoc.ch == '(') {
// Increment the parenthese level
iParenthesesLevel++;
}
// Else if the character is a ) (close parenthese)
else if (scDoc.ch == ')') {
// If the parenthese level is set to zero
// parentheses matched
if (!iParenthesesLevel) {
scDoc.SetState(SCE_CLW_DEFAULT);
}
// Else parenthese level is greater than zero
// still looking for matching parentheses
else {
// Decrement the parenthese level
iParenthesesLevel--;
}
}
}
// Standard Equate State Handling
else if (scDoc.state == SCE_CLW_STANDARD_EQUATE) {
if (!isalnum(scDoc.ch)) {
scDoc.SetState(SCE_CLW_DEFAULT);
}
}
// Integer Constant State Handling
else if (scDoc.state == SCE_CLW_INTEGER_CONSTANT) {
// If the character is not a digit (0-9)
// or character is not a hexidecimal character (A-F)
// or character is not a . (point)
// or character is not a numberic base character (B,O,H)
if (!(isdigit(scDoc.ch)
|| IsAHexCharacter(scDoc.ch, bCaseSensitive)
|| scDoc.ch == '.'
|| IsANumericBaseCharacter(scDoc.ch, bCaseSensitive))) {
// If the number was a real
if (SetNumericConstantState(scDoc)) {
// Colour the matched string to the real constant state
scDoc.ChangeState(SCE_CLW_REAL_CONSTANT);
}
// Else the number was an integer
else {
// Colour the matched string to an integer constant state
scDoc.ChangeState(SCE_CLW_INTEGER_CONSTANT);
}
// Terminate the integer constant state and set to default state
scDoc.SetState(SCE_CLW_DEFAULT);
}
}
//
// Determine if a new state should be entered.
//
// Beginning of Line Handling
if (scDoc.atLineStart) {
// Reset the column 1 label flag
iColumn1Label = false;
// If column 1 character is a label start character
if (IsALabelStart(scDoc.ch)) {
// Label character is found in column 1
// so set column 1 label flag and clear last column 1 label
iColumn1Label = true;
// Set the state to label
scDoc.SetState(SCE_CLW_LABEL);
}
// else if character is a space or tab
else if (IsASpace(scDoc.ch)){
// Set to default state
scDoc.SetState(SCE_CLW_DEFAULT);
}
// else if comment start (!) or is an * (asterisk)
else if (IsACommentStart(scDoc.ch) || scDoc.ch == '*' ) {
// then set the state to comment.
scDoc.SetState(SCE_CLW_COMMENT);
}
// else the character is a ? (question mark)
else if (scDoc.ch == '?') {
// Change to the compiler directive state, move forward,
// colouring the ? (question mark), change back to default state.
scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE);
scDoc.Forward();
scDoc.SetState(SCE_CLW_DEFAULT);
}
// else an invalid character in column 1
else {
// Set to error state
scDoc.SetState(SCE_CLW_ERROR);
}
}
// End of Line Handling
else if (scDoc.atLineEnd) {
// Reset to the default state at the end of each line.
scDoc.SetState(SCE_CLW_DEFAULT);
}
// Default Handling
else {
// If in default state
if (scDoc.state == SCE_CLW_DEFAULT) {
// If is a letter could be a possible statement
if (isalpha(scDoc.ch)) {
// Set the state to Clarion Keyword and verify later
scDoc.SetState(SCE_CLW_KEYWORD);
}
// else is a number
else if (isdigit(scDoc.ch)) {
// Set the state to Integer Constant and verify later
scDoc.SetState(SCE_CLW_INTEGER_CONSTANT);
}
// else if the start of a comment or a | (line continuation)
else if (IsACommentStart(scDoc.ch) || scDoc.ch == '|') {
// then set the state to comment.
scDoc.SetState(SCE_CLW_COMMENT);
}
// else if the character is a ' (single quote)
else if (scDoc.ch == '\'') {
// If the character is also a ' (single quote)
// Embedded Apostrophe
if (scDoc.chNext == '\'') {
// Move forward colouring it as default state
scDoc.ForwardSetState(SCE_CLW_DEFAULT);
}
else {
// move to the next character and then set the state to comment.
scDoc.ForwardSetState(SCE_CLW_STRING);
}
}
// else the character is an @ (ampersand)
else if (scDoc.ch == '@') {
// Case insensitive.
if (!bCaseSensitive) {
// If character is a valid picture token character
if (strchr("DEKNPSTdeknpst", scDoc.chNext) != NULL) {
// Set to the picture string state
scDoc.SetState(SCE_CLW_PICTURE_STRING);
}
}
// Case sensitive
else {
// If character is a valid picture token character
if (strchr("DEKNPST", scDoc.chNext) != NULL) {
// Set the picture string state
scDoc.SetState(SCE_CLW_PICTURE_STRING);
}
}
}
}
}
}
// lexing complete
scDoc.Complete();
}
// Clarion Language Case Sensitive Colouring Procedure
static void ColouriseClarionDocSensitive(Sci_PositionU uiStartPos, Sci_Position iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler) {
ColouriseClarionDoc(uiStartPos, iLength, iInitStyle, wlKeywords, accStyler, true);
}
// Clarion Language Case Insensitive Colouring Procedure
static void ColouriseClarionDocInsensitive(Sci_PositionU uiStartPos, Sci_Position iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler) {
ColouriseClarionDoc(uiStartPos, iLength, iInitStyle, wlKeywords, accStyler, false);
}
// Fill Buffer
static void FillBuffer(Sci_PositionU uiStart, Sci_PositionU uiEnd, Accessor &accStyler, char *szBuffer, Sci_PositionU uiLength) {
Sci_PositionU uiPos = 0;
while ((uiPos < uiEnd - uiStart + 1) && (uiPos < uiLength-1)) {
szBuffer[uiPos] = static_cast<char>(toupper(accStyler[uiStart + uiPos]));
uiPos++;
}
szBuffer[uiPos] = '\0';
}
// Classify Clarion Fold Point
static int ClassifyClarionFoldPoint(int iLevel, const char* szString) {
if (!(isdigit(szString[0]) || (szString[0] == '.'))) {
if (strcmp(szString, "PROCEDURE") == 0) {
// iLevel = SC_FOLDLEVELBASE + 1;
}
else if (strcmp(szString, "MAP") == 0 ||
strcmp(szString,"ACCEPT") == 0 ||
strcmp(szString,"BEGIN") == 0 ||
strcmp(szString,"CASE") == 0 ||
strcmp(szString,"EXECUTE") == 0 ||
strcmp(szString,"IF") == 0 ||
strcmp(szString,"ITEMIZE") == 0 ||
strcmp(szString,"INTERFACE") == 0 ||
strcmp(szString,"JOIN") == 0 ||
strcmp(szString,"LOOP") == 0 ||
strcmp(szString,"MODULE") == 0 ||
strcmp(szString,"RECORD") == 0) {
iLevel++;
}
else if (strcmp(szString, "APPLICATION") == 0 ||
strcmp(szString, "CLASS") == 0 ||
strcmp(szString, "DETAIL") == 0 ||
strcmp(szString, "FILE") == 0 ||
strcmp(szString, "FOOTER") == 0 ||
strcmp(szString, "FORM") == 0 ||
strcmp(szString, "GROUP") == 0 ||
strcmp(szString, "HEADER") == 0 ||
strcmp(szString, "INTERFACE") == 0 ||
strcmp(szString, "MENU") == 0 ||
strcmp(szString, "MENUBAR") == 0 ||
strcmp(szString, "OLE") == 0 ||
strcmp(szString, "OPTION") == 0 ||
strcmp(szString, "QUEUE") == 0 ||
strcmp(szString, "REPORT") == 0 ||
strcmp(szString, "SHEET") == 0 ||
strcmp(szString, "TAB") == 0 ||
strcmp(szString, "TOOLBAR") == 0 ||
strcmp(szString, "VIEW") == 0 ||
strcmp(szString, "WINDOW") == 0) {
iLevel++;
}
else if (strcmp(szString, "END") == 0 ||
strcmp(szString, "UNTIL") == 0 ||
strcmp(szString, "WHILE") == 0) {
iLevel--;
}
}
return(iLevel);
}
// Clarion Language Folding Procedure
static void FoldClarionDoc(Sci_PositionU uiStartPos, Sci_Position iLength, int iInitStyle, WordList *[], Accessor &accStyler) {
Sci_PositionU uiEndPos = uiStartPos + iLength;
Sci_Position iLineCurrent = accStyler.GetLine(uiStartPos);
int iLevelPrev = accStyler.LevelAt(iLineCurrent) & SC_FOLDLEVELNUMBERMASK;
int iLevelCurrent = iLevelPrev;
char chNext = accStyler[uiStartPos];
int iStyle = iInitStyle;
int iStyleNext = accStyler.StyleAt(uiStartPos);
int iVisibleChars = 0;
Sci_Position iLastStart = 0;
for (Sci_PositionU uiPos = uiStartPos; uiPos < uiEndPos; uiPos++) {
char chChar = chNext;
chNext = accStyler.SafeGetCharAt(uiPos + 1);
int iStylePrev = iStyle;
iStyle = iStyleNext;
iStyleNext = accStyler.StyleAt(uiPos + 1);
bool bEOL = (chChar == '\r' && chNext != '\n') || (chChar == '\n');
if (iStylePrev == SCE_CLW_DEFAULT) {
if (iStyle == SCE_CLW_KEYWORD || iStyle == SCE_CLW_STRUCTURE_DATA_TYPE) {
// Store last word start point.
iLastStart = uiPos;
}
}
if (iStylePrev == SCE_CLW_KEYWORD || iStylePrev == SCE_CLW_STRUCTURE_DATA_TYPE) {
if(iswordchar(chChar) && !iswordchar(chNext)) {
char chBuffer[100];
FillBuffer(iLastStart, uiPos, accStyler, chBuffer, sizeof(chBuffer));
iLevelCurrent = ClassifyClarionFoldPoint(iLevelCurrent,chBuffer);
// if ((iLevelCurrent == SC_FOLDLEVELBASE + 1) && iLineCurrent > 1) {
// accStyler.SetLevel(iLineCurrent-1,SC_FOLDLEVELBASE);
// iLevelPrev = SC_FOLDLEVELBASE;
// }
}
}
if (bEOL) {
int iLevel = iLevelPrev;
if ((iLevelCurrent > iLevelPrev) && (iVisibleChars > 0))
iLevel |= SC_FOLDLEVELHEADERFLAG;
if (iLevel != accStyler.LevelAt(iLineCurrent)) {
accStyler.SetLevel(iLineCurrent,iLevel);
}
iLineCurrent++;
iLevelPrev = iLevelCurrent;
iVisibleChars = 0;
}
if (!isspacechar(chChar))
iVisibleChars++;
}
// Fill in the real level of the next line, keeping the current flags
// as they will be filled in later.
int iFlagsNext = accStyler.LevelAt(iLineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
accStyler.SetLevel(iLineCurrent, iLevelPrev | iFlagsNext);
}
// Word List Descriptions
static const char * const rgWordListDescriptions[] = {
"Clarion Keywords",
"Compiler Directives",
"Built-in Procedures and Functions",
"Runtime Expressions",
"Structure and Data Types",
"Attributes",
"Standard Equates",
"Reserved Words (Labels)",
"Reserved Words (Procedure Labels)",
0,
};
// Case Sensitive Clarion Language Lexer
LexerModule lmClw(SCLEX_CLW, ColouriseClarionDocSensitive, "clarion", FoldClarionDoc, rgWordListDescriptions);
// Case Insensitive Clarion Language Lexer
LexerModule lmClwNoCase(SCLEX_CLWNOCASE, ColouriseClarionDocInsensitive, "clarionnocase", FoldClarionDoc, rgWordListDescriptions);

View File

@ -0,0 +1,387 @@
// Scintilla source code edit control
/** @file LexCOBOL.cxx
** Lexer for COBOL
** Based on LexPascal.cxx
** Written by Laurent le Tynevez
** Updated by Simon Steele <s.steele@pnotepad.org> September 2002
** Updated by Mathias Rauen <scite@madshi.net> May 2003 (Delphi adjustments)
** Updated by Rod Falck, Aug 2006 Converted to COBOL
**/
#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;
#define IN_DIVISION 0x01
#define IN_DECLARATIVES 0x02
#define IN_SECTION 0x04
#define IN_PARAGRAPH 0x08
#define IN_FLAGS 0xF
#define NOT_HEADER 0x10
inline bool isCOBOLoperator(char ch)
{
return isoperator(ch);
}
inline bool isCOBOLwordchar(char ch)
{
return IsASCII(ch) && (isalnum(ch) || ch == '-');
}
inline bool isCOBOLwordstart(char ch)
{
return IsASCII(ch) && isalnum(ch);
}
static int CountBits(int nBits)
{
int count = 0;
for (int i = 0; i < 32; ++i)
{
count += nBits & 1;
nBits >>= 1;
}
return count;
}
static void getRange(Sci_PositionU start,
Sci_PositionU end,
Accessor &styler,
char *s,
Sci_PositionU len) {
Sci_PositionU i = 0;
while ((i < end - start + 1) && (i < len-1)) {
s[i] = static_cast<char>(tolower(styler[start + i]));
i++;
}
s[i] = '\0';
}
static void ColourTo(Accessor &styler, Sci_PositionU end, unsigned int attr) {
styler.ColourTo(end, attr);
}
static int classifyWordCOBOL(Sci_PositionU start, Sci_PositionU end, /*WordList &keywords*/WordList *keywordlists[], Accessor &styler, int nContainment, bool *bAarea) {
int ret = 0;
char s[100];
s[0] = '\0';
s[1] = '\0';
getRange(start, end, styler, s, sizeof(s));
int chAttr = SCE_C_IDENTIFIER;
if (isdigit(s[0]) || (s[0] == '.') || (s[0] == 'v')) {
chAttr = SCE_C_NUMBER;
char *p = s + 1;
while (*p) {
if ((!isdigit(*p) && (*p) != 'v') && isCOBOLwordchar(*p)) {
chAttr = SCE_C_IDENTIFIER;
break;
}
++p;
}
}
if (chAttr == SCE_C_IDENTIFIER) {
WordList& a_keywords = *keywordlists[0];
WordList& b_keywords = *keywordlists[1];
WordList& c_keywords = *keywordlists[2];
if (a_keywords.InList(s)) {
chAttr = SCE_C_WORD;
}
else if (b_keywords.InList(s)) {
chAttr = SCE_C_WORD2;
}
else if (c_keywords.InList(s)) {
chAttr = SCE_C_UUID;
}
}
if (*bAarea) {
if (strcmp(s, "division") == 0) {
ret = IN_DIVISION;
// we've determined the containment, anything else is just ignored for those purposes
*bAarea = false;
} else if (strcmp(s, "declaratives") == 0) {
ret = IN_DIVISION | IN_DECLARATIVES;
if (nContainment & IN_DECLARATIVES)
ret |= NOT_HEADER | IN_SECTION;
// we've determined the containment, anything else is just ignored for those purposes
*bAarea = false;
} else if (strcmp(s, "section") == 0) {
ret = (nContainment &~ IN_PARAGRAPH) | IN_SECTION;
// we've determined the containment, anything else is just ignored for those purposes
*bAarea = false;
} else if (strcmp(s, "end") == 0 && (nContainment & IN_DECLARATIVES)) {
ret = IN_DIVISION | IN_DECLARATIVES | IN_SECTION | NOT_HEADER;
} else {
ret = nContainment | IN_PARAGRAPH;
}
}
ColourTo(styler, end, chAttr);
return ret;
}
static void ColouriseCOBOLDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
styler.StartAt(startPos);
int state = initStyle;
if (state == SCE_C_CHARACTER) // Does not leak onto next line
state = SCE_C_DEFAULT;
char chPrev = ' ';
char chNext = styler[startPos];
Sci_PositionU lengthDoc = startPos + length;
int nContainment;
Sci_Position currentLine = styler.GetLine(startPos);
if (currentLine > 0) {
styler.SetLineState(currentLine, styler.GetLineState(currentLine-1));
nContainment = styler.GetLineState(currentLine);
nContainment &= ~NOT_HEADER;
} else {
styler.SetLineState(currentLine, 0);
nContainment = 0;
}
styler.StartSegment(startPos);
bool bNewLine = true;
bool bAarea = !isspacechar(chNext);
int column = 0;
for (Sci_PositionU i = startPos; i < lengthDoc; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
++column;
if (bNewLine) {
column = 0;
}
if (column <= 1 && !bAarea) {
bAarea = !isspacechar(ch);
}
bool bSetNewLine = false;
if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
// Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
// Avoid triggering two times on Dos/Win
// End of line
if (state == SCE_C_CHARACTER) {
ColourTo(styler, i, state);
state = SCE_C_DEFAULT;
}
styler.SetLineState(currentLine, nContainment);
currentLine++;
bSetNewLine = true;
if (nContainment & NOT_HEADER)
nContainment &= ~(NOT_HEADER | IN_DECLARATIVES | IN_SECTION);
}
if (styler.IsLeadByte(ch)) {
chNext = styler.SafeGetCharAt(i + 2);
chPrev = ' ';
i += 1;
continue;
}
if (state == SCE_C_DEFAULT) {
if (isCOBOLwordstart(ch) || (ch == '$' && IsASCII(chNext) && isalpha(chNext))) {
ColourTo(styler, i-1, state);
state = SCE_C_IDENTIFIER;
} else if (column == 6 && (ch == '*' || ch == '/')) {
// Cobol comment line: asterisk in column 7.
ColourTo(styler, i-1, state);
state = SCE_C_COMMENTLINE;
} else if (ch == '*' && chNext == '>') {
// Cobol inline comment: asterisk, followed by greater than.
ColourTo(styler, i-1, state);
state = SCE_C_COMMENTLINE;
} else if (column == 0 && ch == '*' && chNext != '*') {
ColourTo(styler, i-1, state);
state = SCE_C_COMMENTLINE;
} else if (column == 0 && ch == '/' && chNext != '*') {
ColourTo(styler, i-1, state);
state = SCE_C_COMMENTLINE;
} else if (column == 0 && ch == '*' && chNext == '*') {
ColourTo(styler, i-1, state);
state = SCE_C_COMMENTDOC;
} else if (column == 0 && ch == '/' && chNext == '*') {
ColourTo(styler, i-1, state);
state = SCE_C_COMMENTDOC;
} else if (ch == '"') {
ColourTo(styler, i-1, state);
state = SCE_C_STRING;
} else if (ch == '\'') {
ColourTo(styler, i-1, state);
state = SCE_C_CHARACTER;
} else if (ch == '?' && column == 0) {
ColourTo(styler, i-1, state);
state = SCE_C_PREPROCESSOR;
} else if (isCOBOLoperator(ch)) {
ColourTo(styler, i-1, state);
ColourTo(styler, i, SCE_C_OPERATOR);
}
} else if (state == SCE_C_IDENTIFIER) {
if (!isCOBOLwordchar(ch)) {
int lStateChange = classifyWordCOBOL(styler.GetStartSegment(), i - 1, keywordlists, styler, nContainment, &bAarea);
if(lStateChange != 0) {
styler.SetLineState(currentLine, lStateChange);
nContainment = lStateChange;
}
state = SCE_C_DEFAULT;
chNext = styler.SafeGetCharAt(i + 1);
if (column == 6 && (ch == '*' || ch == '/')) {
state = SCE_C_COMMENTLINE;
} else if (ch == '"') {
state = SCE_C_STRING;
} else if (ch == '\'') {
state = SCE_C_CHARACTER;
} else if (isCOBOLoperator(ch)) {
ColourTo(styler, i, SCE_C_OPERATOR);
}
}
} else {
if (state == SCE_C_PREPROCESSOR) {
if ((ch == '\r' || ch == '\n') && !(chPrev == '\\' || chPrev == '\r')) {
ColourTo(styler, i-1, state);
state = SCE_C_DEFAULT;
}
} else if (state == SCE_C_COMMENT) {
if (ch == '\r' || ch == '\n') {
ColourTo(styler, i-1, state);
state = SCE_C_DEFAULT;
}
} else if (state == SCE_C_COMMENTDOC) {
if (ch == '\r' || ch == '\n') {
if (((i > styler.GetStartSegment() + 2) || (
(initStyle == SCE_C_COMMENTDOC) &&
(styler.GetStartSegment() == static_cast<Sci_PositionU>(startPos))))) {
ColourTo(styler, i-1, state);
state = SCE_C_DEFAULT;
}
}
} else if (state == SCE_C_COMMENTLINE) {
if (ch == '\r' || ch == '\n') {
ColourTo(styler, i-1, state);
state = SCE_C_DEFAULT;
}
} else if (state == SCE_C_STRING) {
if (ch == '"') {
ColourTo(styler, i, state);
state = SCE_C_DEFAULT;
} else if (ch == '\r' || ch == '\n') {
ColourTo(styler, i-1, state);
state = SCE_C_DEFAULT;
}
} else if (state == SCE_C_CHARACTER) {
if (ch == '\'') {
ColourTo(styler, i, state);
state = SCE_C_DEFAULT;
}
}
}
chPrev = ch;
bNewLine = bSetNewLine;
if (bNewLine)
{
bAarea = false;
}
}
ColourTo(styler, lengthDoc - 1, state);
}
static void FoldCOBOLDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[],
Accessor &styler) {
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = lineCurrent > 0 ? styler.LevelAt(lineCurrent - 1) & SC_FOLDLEVELNUMBERMASK : 0xFFF;
char chNext = styler[startPos];
bool bNewLine = true;
bool bAarea = !isspacechar(chNext);
int column = 0;
bool bComment = false;
for (Sci_PositionU i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
++column;
if (bNewLine) {
column = 0;
bComment = (ch == '*' || ch == '/' || ch == '?');
}
if (column <= 1 && !bAarea) {
bAarea = !isspacechar(ch);
}
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
if (atEOL) {
int nContainment = styler.GetLineState(lineCurrent);
int lev = CountBits(nContainment & IN_FLAGS) | SC_FOLDLEVELBASE;
if (bAarea && !bComment)
--lev;
if (visibleChars == 0 && foldCompact)
lev |= SC_FOLDLEVELWHITEFLAG;
if ((bAarea) && (visibleChars > 0) && !(nContainment & NOT_HEADER) && !bComment)
lev |= SC_FOLDLEVELHEADERFLAG;
if (lev != styler.LevelAt(lineCurrent)) {
styler.SetLevel(lineCurrent, lev);
}
if ((lev & SC_FOLDLEVELNUMBERMASK) <= (levelPrev & SC_FOLDLEVELNUMBERMASK)) {
// this level is at the same level or less than the previous line
// therefore these is nothing for the previous header to collapse, so remove the header
styler.SetLevel(lineCurrent - 1, levelPrev & ~SC_FOLDLEVELHEADERFLAG);
}
levelPrev = lev;
visibleChars = 0;
bAarea = false;
bNewLine = true;
lineCurrent++;
} else {
bNewLine = false;
}
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 COBOLWordListDesc[] = {
"A Keywords",
"B Keywords",
"Extended Keywords",
0
};
LexerModule lmCOBOL(SCLEX_COBOL, ColouriseCOBOLDoc, "COBOL", FoldCOBOLDoc, COBOLWordListDesc);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,570 @@
// Scintilla source code edit control
// Encoding: UTF-8
/** @file LexCSS.cxx
** Lexer for Cascading Style Sheets
** Written by Jakub Vrána
** Improved by Philippe Lhoste (CSS2)
** Improved by Ross McKay (SCSS mode; see http://sass-lang.com/ )
**/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
// TODO: handle SCSS nested properties like font: { weight: bold; size: 1em; }
// TODO: handle SCSS interpolation: #{}
// TODO: add features for Less if somebody feels like contributing; http://lesscss.org/
// TODO: refactor this monster so that the next poor slob can read it!
#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;
static inline bool IsAWordChar(const unsigned int ch) {
/* FIXME:
* The CSS spec allows "ISO 10646 characters U+00A1 and higher" to be treated as word chars.
* Unfortunately, we are only getting string bytes here, and not full unicode characters. We cannot guarantee
* that our byte is between U+0080 - U+00A0 (to return false), so we have to allow all characters U+0080 and higher
*/
return ch >= 0x80 || isalnum(ch) || ch == '-' || ch == '_';
}
inline bool IsCssOperator(const int ch) {
if (!((ch < 0x80) && isalnum(ch)) &&
(ch == '{' || ch == '}' || ch == ':' || ch == ',' || ch == ';' ||
ch == '.' || ch == '#' || ch == '!' || ch == '@' ||
/* CSS2 */
ch == '*' || ch == '>' || ch == '+' || ch == '=' || ch == '~' || ch == '|' ||
ch == '[' || ch == ']' || ch == '(' || ch == ')')) {
return true;
}
return false;
}
// look behind (from start of document to our start position) to determine current nesting level
inline int NestingLevelLookBehind(Sci_PositionU startPos, Accessor &styler) {
int ch;
int nestingLevel = 0;
for (Sci_PositionU i = 0; i < startPos; i++) {
ch = styler.SafeGetCharAt(i);
if (ch == '{')
nestingLevel++;
else if (ch == '}')
nestingLevel--;
}
return nestingLevel;
}
static void ColouriseCssDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], Accessor &styler) {
WordList &css1Props = *keywordlists[0];
WordList &pseudoClasses = *keywordlists[1];
WordList &css2Props = *keywordlists[2];
WordList &css3Props = *keywordlists[3];
WordList &pseudoElements = *keywordlists[4];
WordList &exProps = *keywordlists[5];
WordList &exPseudoClasses = *keywordlists[6];
WordList &exPseudoElements = *keywordlists[7];
StyleContext sc(startPos, length, initStyle, styler);
int lastState = -1; // before operator
int lastStateC = -1; // before comment
int lastStateS = -1; // before single-quoted/double-quoted string
int lastStateVar = -1; // before variable (SCSS)
int lastStateVal = -1; // before value (SCSS)
int op = ' '; // last operator
int opPrev = ' '; // last operator
bool insideParentheses = false; // true if currently in a CSS url() or similar construct
// property lexer.css.scss.language
// Set to 1 for Sassy CSS (.scss)
bool isScssDocument = styler.GetPropertyInt("lexer.css.scss.language") != 0;
// property lexer.css.less.language
// Set to 1 for Less CSS (.less)
bool isLessDocument = styler.GetPropertyInt("lexer.css.less.language") != 0;
// property lexer.css.hss.language
// Set to 1 for HSS (.hss)
bool isHssDocument = styler.GetPropertyInt("lexer.css.hss.language") != 0;
// SCSS/LESS/HSS have the concept of variable
bool hasVariables = isScssDocument || isLessDocument || isHssDocument;
char varPrefix = 0;
if (hasVariables)
varPrefix = isLessDocument ? '@' : '$';
// SCSS/LESS/HSS support single-line comments
typedef enum _CommentModes { eCommentBlock = 0, eCommentLine = 1} CommentMode;
CommentMode comment_mode = eCommentBlock;
bool hasSingleLineComments = isScssDocument || isLessDocument || isHssDocument;
// must keep track of nesting level in document types that support it (SCSS/LESS/HSS)
bool hasNesting = false;
int nestingLevel = 0;
if (isScssDocument || isLessDocument || isHssDocument) {
hasNesting = true;
nestingLevel = NestingLevelLookBehind(startPos, styler);
}
// "the loop"
for (; sc.More(); sc.Forward()) {
if (sc.state == SCE_CSS_COMMENT && ((comment_mode == eCommentBlock && sc.Match('*', '/')) || (comment_mode == eCommentLine && sc.atLineEnd))) {
if (lastStateC == -1) {
// backtrack to get last state:
// comments are like whitespace, so we must return to the previous state
Sci_PositionU i = startPos;
for (; i > 0; i--) {
if ((lastStateC = styler.StyleAt(i-1)) != SCE_CSS_COMMENT) {
if (lastStateC == SCE_CSS_OPERATOR) {
op = styler.SafeGetCharAt(i-1);
opPrev = styler.SafeGetCharAt(i-2);
while (--i) {
lastState = styler.StyleAt(i-1);
if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT)
break;
}
if (i == 0)
lastState = SCE_CSS_DEFAULT;
}
break;
}
}
if (i == 0)
lastStateC = SCE_CSS_DEFAULT;
}
if (comment_mode == eCommentBlock) {
sc.Forward();
sc.ForwardSetState(lastStateC);
} else /* eCommentLine */ {
sc.SetState(lastStateC);
}
}
if (sc.state == SCE_CSS_COMMENT)
continue;
if (sc.state == SCE_CSS_DOUBLESTRING || sc.state == SCE_CSS_SINGLESTRING) {
if (sc.ch != (sc.state == SCE_CSS_DOUBLESTRING ? '\"' : '\''))
continue;
Sci_PositionU i = sc.currentPos;
while (i && styler[i-1] == '\\')
i--;
if ((sc.currentPos - i) % 2 == 1)
continue;
sc.ForwardSetState(lastStateS);
}
if (sc.state == SCE_CSS_OPERATOR) {
if (op == ' ') {
Sci_PositionU i = startPos;
op = styler.SafeGetCharAt(i-1);
opPrev = styler.SafeGetCharAt(i-2);
while (--i) {
lastState = styler.StyleAt(i-1);
if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT)
break;
}
}
switch (op) {
case '@':
if (lastState == SCE_CSS_DEFAULT || hasNesting)
sc.SetState(SCE_CSS_DIRECTIVE);
break;
case '>':
case '+':
if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID ||
lastState == SCE_CSS_PSEUDOCLASS || lastState == SCE_CSS_EXTENDED_PSEUDOCLASS || lastState == SCE_CSS_UNKNOWN_PSEUDOCLASS)
sc.SetState(SCE_CSS_DEFAULT);
break;
case '[':
if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID ||
lastState == SCE_CSS_PSEUDOCLASS || lastState == SCE_CSS_EXTENDED_PSEUDOCLASS || lastState == SCE_CSS_UNKNOWN_PSEUDOCLASS)
sc.SetState(SCE_CSS_ATTRIBUTE);
break;
case ']':
if (lastState == SCE_CSS_ATTRIBUTE)
sc.SetState(SCE_CSS_TAG);
break;
case '{':
nestingLevel++;
switch (lastState) {
case SCE_CSS_GROUP_RULE:
sc.SetState(SCE_CSS_DEFAULT);
break;
case SCE_CSS_TAG:
case SCE_CSS_DIRECTIVE:
sc.SetState(SCE_CSS_IDENTIFIER);
break;
}
break;
case '}':
if (--nestingLevel < 0)
nestingLevel = 0;
switch (lastState) {
case SCE_CSS_DEFAULT:
case SCE_CSS_VALUE:
case SCE_CSS_IMPORTANT:
case SCE_CSS_IDENTIFIER:
case SCE_CSS_IDENTIFIER2:
case SCE_CSS_IDENTIFIER3:
if (hasNesting)
sc.SetState(nestingLevel > 0 ? SCE_CSS_IDENTIFIER : SCE_CSS_DEFAULT);
else
sc.SetState(SCE_CSS_DEFAULT);
break;
}
break;
case '(':
if (lastState == SCE_CSS_PSEUDOCLASS)
sc.SetState(SCE_CSS_TAG);
else if (lastState == SCE_CSS_EXTENDED_PSEUDOCLASS)
sc.SetState(SCE_CSS_EXTENDED_PSEUDOCLASS);
break;
case ')':
if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID ||
lastState == SCE_CSS_PSEUDOCLASS || lastState == SCE_CSS_EXTENDED_PSEUDOCLASS || lastState == SCE_CSS_UNKNOWN_PSEUDOCLASS ||
lastState == SCE_CSS_PSEUDOELEMENT || lastState == SCE_CSS_EXTENDED_PSEUDOELEMENT)
sc.SetState(SCE_CSS_TAG);
break;
case ':':
switch (lastState) {
case SCE_CSS_TAG:
case SCE_CSS_DEFAULT:
case SCE_CSS_CLASS:
case SCE_CSS_ID:
case SCE_CSS_PSEUDOCLASS:
case SCE_CSS_EXTENDED_PSEUDOCLASS:
case SCE_CSS_UNKNOWN_PSEUDOCLASS:
case SCE_CSS_PSEUDOELEMENT:
case SCE_CSS_EXTENDED_PSEUDOELEMENT:
sc.SetState(SCE_CSS_PSEUDOCLASS);
break;
case SCE_CSS_IDENTIFIER:
case SCE_CSS_IDENTIFIER2:
case SCE_CSS_IDENTIFIER3:
case SCE_CSS_EXTENDED_IDENTIFIER:
case SCE_CSS_UNKNOWN_IDENTIFIER:
case SCE_CSS_VARIABLE:
sc.SetState(SCE_CSS_VALUE);
lastStateVal = lastState;
break;
}
break;
case '.':
if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID ||
lastState == SCE_CSS_PSEUDOCLASS || lastState == SCE_CSS_EXTENDED_PSEUDOCLASS || lastState == SCE_CSS_UNKNOWN_PSEUDOCLASS)
sc.SetState(SCE_CSS_CLASS);
break;
case '#':
if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID ||
lastState == SCE_CSS_PSEUDOCLASS || lastState == SCE_CSS_EXTENDED_PSEUDOCLASS || lastState == SCE_CSS_UNKNOWN_PSEUDOCLASS)
sc.SetState(SCE_CSS_ID);
break;
case ',':
case '|':
case '~':
if (lastState == SCE_CSS_TAG)
sc.SetState(SCE_CSS_DEFAULT);
break;
case ';':
switch (lastState) {
case SCE_CSS_DIRECTIVE:
if (hasNesting) {
sc.SetState(nestingLevel > 0 ? SCE_CSS_IDENTIFIER : SCE_CSS_DEFAULT);
} else {
sc.SetState(SCE_CSS_DEFAULT);
}
break;
case SCE_CSS_VALUE:
case SCE_CSS_IMPORTANT:
// data URLs can have semicolons; simplistically check for wrapping parentheses and move along
if (insideParentheses) {
sc.SetState(lastState);
} else {
if (lastStateVal == SCE_CSS_VARIABLE) {
sc.SetState(SCE_CSS_DEFAULT);
} else {
sc.SetState(SCE_CSS_IDENTIFIER);
}
}
break;
case SCE_CSS_VARIABLE:
if (lastStateVar == SCE_CSS_VALUE) {
// data URLs can have semicolons; simplistically check for wrapping parentheses and move along
if (insideParentheses) {
sc.SetState(SCE_CSS_VALUE);
} else {
sc.SetState(SCE_CSS_IDENTIFIER);
}
} else {
sc.SetState(SCE_CSS_DEFAULT);
}
break;
}
break;
case '!':
if (lastState == SCE_CSS_VALUE)
sc.SetState(SCE_CSS_IMPORTANT);
break;
}
}
if (sc.ch == '*' && sc.state == SCE_CSS_DEFAULT) {
sc.SetState(SCE_CSS_TAG);
continue;
}
// check for inside parentheses (whether part of an "operator" or not)
if (sc.ch == '(')
insideParentheses = true;
else if (sc.ch == ')')
insideParentheses = false;
// SCSS special modes
if (hasVariables) {
// variable name
if (sc.ch == varPrefix) {
switch (sc.state) {
case SCE_CSS_DEFAULT:
if (isLessDocument) // give priority to pseudo elements
break;
// Falls through.
case SCE_CSS_VALUE:
lastStateVar = sc.state;
sc.SetState(SCE_CSS_VARIABLE);
continue;
}
}
if (sc.state == SCE_CSS_VARIABLE) {
if (IsAWordChar(sc.ch)) {
// still looking at the variable name
continue;
}
if (lastStateVar == SCE_CSS_VALUE) {
// not looking at the variable name any more, and it was part of a value
sc.SetState(SCE_CSS_VALUE);
}
}
// nested rule parent selector
if (sc.ch == '&') {
switch (sc.state) {
case SCE_CSS_DEFAULT:
case SCE_CSS_IDENTIFIER:
sc.SetState(SCE_CSS_TAG);
continue;
}
}
}
// nesting rules that apply to SCSS and Less
if (hasNesting) {
// check for nested rule selector
if (sc.state == SCE_CSS_IDENTIFIER && (IsAWordChar(sc.ch) || sc.ch == ':' || sc.ch == '.' || sc.ch == '#')) {
// look ahead to see whether { comes before next ; and }
Sci_PositionU endPos = startPos + length;
int ch;
for (Sci_PositionU i = sc.currentPos; i < endPos; i++) {
ch = styler.SafeGetCharAt(i);
if (ch == ';' || ch == '}')
break;
if (ch == '{') {
sc.SetState(SCE_CSS_DEFAULT);
continue;
}
}
}
}
if (IsAWordChar(sc.ch)) {
if (sc.state == SCE_CSS_DEFAULT)
sc.SetState(SCE_CSS_TAG);
continue;
}
if (IsAWordChar(sc.chPrev) && (
sc.state == SCE_CSS_IDENTIFIER || sc.state == SCE_CSS_IDENTIFIER2 ||
sc.state == SCE_CSS_IDENTIFIER3 || sc.state == SCE_CSS_EXTENDED_IDENTIFIER ||
sc.state == SCE_CSS_UNKNOWN_IDENTIFIER ||
sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_PSEUDOELEMENT ||
sc.state == SCE_CSS_EXTENDED_PSEUDOCLASS || sc.state == SCE_CSS_EXTENDED_PSEUDOELEMENT ||
sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS ||
sc.state == SCE_CSS_IMPORTANT ||
sc.state == SCE_CSS_DIRECTIVE
)) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
char *s2 = s;
while (*s2 && !IsAWordChar(*s2))
s2++;
switch (sc.state) {
case SCE_CSS_IDENTIFIER:
case SCE_CSS_IDENTIFIER2:
case SCE_CSS_IDENTIFIER3:
case SCE_CSS_EXTENDED_IDENTIFIER:
case SCE_CSS_UNKNOWN_IDENTIFIER:
if (css1Props.InList(s2))
sc.ChangeState(SCE_CSS_IDENTIFIER);
else if (css2Props.InList(s2))
sc.ChangeState(SCE_CSS_IDENTIFIER2);
else if (css3Props.InList(s2))
sc.ChangeState(SCE_CSS_IDENTIFIER3);
else if (exProps.InList(s2))
sc.ChangeState(SCE_CSS_EXTENDED_IDENTIFIER);
else
sc.ChangeState(SCE_CSS_UNKNOWN_IDENTIFIER);
break;
case SCE_CSS_PSEUDOCLASS:
case SCE_CSS_PSEUDOELEMENT:
case SCE_CSS_EXTENDED_PSEUDOCLASS:
case SCE_CSS_EXTENDED_PSEUDOELEMENT:
case SCE_CSS_UNKNOWN_PSEUDOCLASS:
if (op == ':' && opPrev != ':' && pseudoClasses.InList(s2))
sc.ChangeState(SCE_CSS_PSEUDOCLASS);
else if (opPrev == ':' && pseudoElements.InList(s2))
sc.ChangeState(SCE_CSS_PSEUDOELEMENT);
else if ((op == ':' || (op == '(' && lastState == SCE_CSS_EXTENDED_PSEUDOCLASS)) && opPrev != ':' && exPseudoClasses.InList(s2))
sc.ChangeState(SCE_CSS_EXTENDED_PSEUDOCLASS);
else if (opPrev == ':' && exPseudoElements.InList(s2))
sc.ChangeState(SCE_CSS_EXTENDED_PSEUDOELEMENT);
else
sc.ChangeState(SCE_CSS_UNKNOWN_PSEUDOCLASS);
break;
case SCE_CSS_IMPORTANT:
if (strcmp(s2, "important") != 0)
sc.ChangeState(SCE_CSS_VALUE);
break;
case SCE_CSS_DIRECTIVE:
if (op == '@' && (strcmp(s2, "media") == 0 || strcmp(s2, "supports") == 0 || strcmp(s2, "document") == 0 || strcmp(s2, "-moz-document") == 0))
sc.ChangeState(SCE_CSS_GROUP_RULE);
break;
}
}
if (sc.ch != '.' && sc.ch != ':' && sc.ch != '#' && (
sc.state == SCE_CSS_CLASS || sc.state == SCE_CSS_ID ||
(sc.ch != '(' && sc.ch != ')' && ( /* This line of the condition makes it possible to extend pseudo-classes with parentheses */
sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_PSEUDOELEMENT ||
sc.state == SCE_CSS_EXTENDED_PSEUDOCLASS || sc.state == SCE_CSS_EXTENDED_PSEUDOELEMENT ||
sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS
))
))
sc.SetState(SCE_CSS_TAG);
if (sc.Match('/', '*')) {
lastStateC = sc.state;
comment_mode = eCommentBlock;
sc.SetState(SCE_CSS_COMMENT);
sc.Forward();
} else if (hasSingleLineComments && sc.Match('/', '/') && !insideParentheses) {
// note that we've had to treat ([...]// as the start of a URL not a comment, e.g. url(http://example.com), url(//example.com)
lastStateC = sc.state;
comment_mode = eCommentLine;
sc.SetState(SCE_CSS_COMMENT);
sc.Forward();
} else if ((sc.state == SCE_CSS_VALUE || sc.state == SCE_CSS_ATTRIBUTE)
&& (sc.ch == '\"' || sc.ch == '\'')) {
lastStateS = sc.state;
sc.SetState((sc.ch == '\"' ? SCE_CSS_DOUBLESTRING : SCE_CSS_SINGLESTRING));
} else if (IsCssOperator(sc.ch)
&& (sc.state != SCE_CSS_ATTRIBUTE || sc.ch == ']')
&& (sc.state != SCE_CSS_VALUE || sc.ch == ';' || sc.ch == '}' || sc.ch == '!')
&& ((sc.state != SCE_CSS_DIRECTIVE && sc.state != SCE_CSS_GROUP_RULE) || sc.ch == ';' || sc.ch == '{')
) {
if (sc.state != SCE_CSS_OPERATOR)
lastState = sc.state;
sc.SetState(SCE_CSS_OPERATOR);
op = sc.ch;
opPrev = sc.chPrev;
}
}
sc.Complete();
}
static void FoldCSSDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
bool inComment = (styler.StyleAt(startPos-1) == SCE_CSS_COMMENT);
for (Sci_PositionU i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
int style = styler.StyleAt(i);
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
if (foldComment) {
if (!inComment && (style == SCE_CSS_COMMENT))
levelCurrent++;
else if (inComment && (style != SCE_CSS_COMMENT))
levelCurrent--;
inComment = (style == SCE_CSS_COMMENT);
}
if (style == SCE_CSS_OPERATOR) {
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 cssWordListDesc[] = {
"CSS1 Properties",
"Pseudo-classes",
"CSS2 Properties",
"CSS3 Properties",
"Pseudo-elements",
"Browser-Specific CSS Properties",
"Browser-Specific Pseudo-classes",
"Browser-Specific Pseudo-elements",
0
};
LexerModule lmCss(SCLEX_CSS, ColouriseCssDoc, "css", FoldCSSDoc, cssWordListDesc);

View File

@ -0,0 +1,329 @@
// Scintilla source code edit control
/** @file LexCaml.cxx
** Lexer for Objective Caml.
**/
// Copyright 2005-2009 by Robert Roessler <robertr@rftp.com>
// The License.txt file describes the conditions under which this software may be distributed.
/* Release History
20050204 Initial release.
20050205 Quick compiler standards/"cleanliness" adjustment.
20050206 Added cast for IsLeadByte().
20050209 Changes to "external" build support.
20050306 Fix for 1st-char-in-doc "corner" case.
20050502 Fix for [harmless] one-past-the-end coloring.
20050515 Refined numeric token recognition logic.
20051125 Added 2nd "optional" keywords class.
20051129 Support "magic" (read-only) comments for RCaml.
20051204 Swtich to using StyleContext infrastructure.
20090629 Add full Standard ML '97 support.
*/
#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"
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wcomma"
#endif
// Since the Microsoft __iscsym[f] funcs are not ANSI...
inline int iscaml(int c) {return isalnum(c) || c == '_';}
inline int iscamlf(int c) {return isalpha(c) || c == '_';}
static const int baseT[24] = {
0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A - L */
0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0,16 /* M - X */
};
using namespace Lexilla;
static void ColouriseCamlDoc(
Sci_PositionU startPos, Sci_Position length,
int initStyle,
WordList *keywordlists[],
Accessor &styler)
{
// initialize styler
StyleContext sc(startPos, length, initStyle, styler);
Sci_PositionU chToken = 0;
int chBase = 0, chLit = 0;
WordList& keywords = *keywordlists[0];
WordList& keywords2 = *keywordlists[1];
WordList& keywords3 = *keywordlists[2];
const bool isSML = keywords.InList("andalso");
const int useMagic = styler.GetPropertyInt("lexer.caml.magic", 0);
// set up [initial] state info (terminating states that shouldn't "bleed")
const int state_ = sc.state & 0x0f;
if (state_ <= SCE_CAML_CHAR
|| (isSML && state_ == SCE_CAML_STRING))
sc.state = SCE_CAML_DEFAULT;
int nesting = (state_ >= SCE_CAML_COMMENT)? (state_ - SCE_CAML_COMMENT): 0;
// foreach char in range...
while (sc.More()) {
// set up [per-char] state info
int state2 = -1; // (ASSUME no state change)
Sci_Position chColor = sc.currentPos - 1;// (ASSUME standard coloring range)
bool advance = true; // (ASSUME scanner "eats" 1 char)
// step state machine
switch (sc.state & 0x0f) {
case SCE_CAML_DEFAULT:
chToken = sc.currentPos; // save [possible] token start (JIC)
// it's wide open; what do we have?
if (iscamlf(sc.ch))
state2 = SCE_CAML_IDENTIFIER;
else if (!isSML && sc.Match('`') && iscamlf(sc.chNext))
state2 = SCE_CAML_TAGNAME;
else if (!isSML && sc.Match('#') && isdigit(sc.chNext))
state2 = SCE_CAML_LINENUM;
else if (isdigit(sc.ch)) {
// it's a number, assume base 10
state2 = SCE_CAML_NUMBER, chBase = 10;
if (sc.Match('0')) {
// there MAY be a base specified...
const char* baseC = "bBoOxX";
if (isSML) {
if (sc.chNext == 'w')
sc.Forward(); // (consume SML "word" indicator)
baseC = "x";
}
// ... change to specified base AS REQUIRED
if (strchr(baseC, sc.chNext))
chBase = baseT[tolower(sc.chNext) - 'a'], sc.Forward();
}
} else if (!isSML && sc.Match('\'')) // (Caml char literal?)
state2 = SCE_CAML_CHAR, chLit = 0;
else if (isSML && sc.Match('#', '"')) // (SML char literal?)
state2 = SCE_CAML_CHAR, sc.Forward();
else if (sc.Match('"'))
state2 = SCE_CAML_STRING;
else if (sc.Match('(', '*'))
state2 = SCE_CAML_COMMENT, sc.Forward(), sc.ch = ' '; // (*)...
else if (strchr("!?~" /* Caml "prefix-symbol" */
"=<>@^|&+-*/$%" /* Caml "infix-symbol" */
"()[]{};,:.#", sc.ch) // Caml "bracket" or ;,:.#
// SML "extra" ident chars
|| (isSML && (sc.Match('\\') || sc.Match('`'))))
state2 = SCE_CAML_OPERATOR;
break;
case SCE_CAML_IDENTIFIER:
// [try to] interpret as [additional] identifier char
if (!(iscaml(sc.ch) || sc.Match('\''))) {
const Sci_Position n = sc.currentPos - chToken;
if (n < 24) {
// length is believable as keyword, [re-]construct token
char t[24];
for (Sci_Position i = -n; i < 0; i++)
t[n + i] = static_cast<char>(sc.GetRelative(i));
t[n] = '\0';
// special-case "_" token as KEYWORD
if ((n == 1 && sc.chPrev == '_') || keywords.InList(t))
sc.ChangeState(SCE_CAML_KEYWORD);
else if (keywords2.InList(t))
sc.ChangeState(SCE_CAML_KEYWORD2);
else if (keywords3.InList(t))
sc.ChangeState(SCE_CAML_KEYWORD3);
}
state2 = SCE_CAML_DEFAULT, advance = false;
}
break;
case SCE_CAML_TAGNAME:
// [try to] interpret as [additional] tagname char
if (!(iscaml(sc.ch) || sc.Match('\'')))
state2 = SCE_CAML_DEFAULT, advance = false;
break;
/*case SCE_CAML_KEYWORD:
case SCE_CAML_KEYWORD2:
case SCE_CAML_KEYWORD3:
// [try to] interpret as [additional] keyword char
if (!iscaml(ch))
state2 = SCE_CAML_DEFAULT, advance = false;
break;*/
case SCE_CAML_LINENUM:
// [try to] interpret as [additional] linenum directive char
if (!isdigit(sc.ch))
state2 = SCE_CAML_DEFAULT, advance = false;
break;
case SCE_CAML_OPERATOR: {
// [try to] interpret as [additional] operator char
const char* o = 0;
if (iscaml(sc.ch) || isspace(sc.ch) // ident or whitespace
|| (o = strchr(")]};,\'\"#", sc.ch),o) // "termination" chars
|| (!isSML && sc.Match('`')) // Caml extra term char
|| (!strchr("!$%&*+-./:<=>?@^|~", sc.ch)// "operator" chars
// SML extra ident chars
&& !(isSML && (sc.Match('\\') || sc.Match('`'))))) {
// check for INCLUSIVE termination
if (o && strchr(")]};,", sc.ch)) {
if ((sc.Match(')') && sc.chPrev == '(')
|| (sc.Match(']') && sc.chPrev == '['))
// special-case "()" and "[]" tokens as KEYWORDS
sc.ChangeState(SCE_CAML_KEYWORD);
chColor++;
} else
advance = false;
state2 = SCE_CAML_DEFAULT;
}
break;
}
case SCE_CAML_NUMBER:
// [try to] interpret as [additional] numeric literal char
if ((!isSML && sc.Match('_')) || IsADigit(sc.ch, chBase))
break;
// how about an integer suffix?
if (!isSML && (sc.Match('l') || sc.Match('L') || sc.Match('n'))
&& (sc.chPrev == '_' || IsADigit(sc.chPrev, chBase)))
break;
// or a floating-point literal?
if (chBase == 10) {
// with a decimal point?
if (sc.Match('.')
&& ((!isSML && sc.chPrev == '_')
|| IsADigit(sc.chPrev, chBase)))
break;
// with an exponent? (I)
if ((sc.Match('e') || sc.Match('E'))
&& ((!isSML && (sc.chPrev == '.' || sc.chPrev == '_'))
|| IsADigit(sc.chPrev, chBase)))
break;
// with an exponent? (II)
if (((!isSML && (sc.Match('+') || sc.Match('-')))
|| (isSML && sc.Match('~')))
&& (sc.chPrev == 'e' || sc.chPrev == 'E'))
break;
}
// it looks like we have run out of number
state2 = SCE_CAML_DEFAULT, advance = false;
break;
case SCE_CAML_CHAR:
if (!isSML) {
// [try to] interpret as [additional] char literal char
if (sc.Match('\\')) {
chLit = 1; // (definitely IS a char literal)
if (sc.chPrev == '\\')
sc.ch = ' '; // (...\\')
// should we be terminating - one way or another?
} else if ((sc.Match('\'') && sc.chPrev != '\\')
|| sc.atLineEnd) {
state2 = SCE_CAML_DEFAULT;
if (sc.Match('\''))
chColor++;
else
sc.ChangeState(SCE_CAML_IDENTIFIER);
// ... maybe a char literal, maybe not
} else if (chLit < 1 && sc.currentPos - chToken >= 2)
sc.ChangeState(SCE_CAML_IDENTIFIER), advance = false;
break;
}/* else
// fall through for SML char literal (handle like string) */
// Falls through.
case SCE_CAML_STRING:
// [try to] interpret as [additional] [SML char/] string literal char
if (isSML && sc.Match('\\') && sc.chPrev != '\\' && isspace(sc.chNext))
state2 = SCE_CAML_WHITE;
else if (sc.Match('\\') && sc.chPrev == '\\')
sc.ch = ' '; // (...\\")
// should we be terminating - one way or another?
else if ((sc.Match('"') && sc.chPrev != '\\')
|| (isSML && sc.atLineEnd)) {
state2 = SCE_CAML_DEFAULT;
if (sc.Match('"'))
chColor++;
}
break;
case SCE_CAML_WHITE:
// [try to] interpret as [additional] SML embedded whitespace char
if (sc.Match('\\')) {
// style this puppy NOW...
state2 = SCE_CAML_STRING, sc.ch = ' ' /* (...\") */, chColor++,
styler.ColourTo(chColor, SCE_CAML_WHITE), styler.Flush();
// ... then backtrack to determine original SML literal type
Sci_Position p = chColor - 2;
for (; p >= 0 && styler.StyleAt(p) == SCE_CAML_WHITE; p--) ;
if (p >= 0)
state2 = static_cast<int>(styler.StyleAt(p));
// take care of state change NOW
sc.ChangeState(state2), state2 = -1;
}
break;
case SCE_CAML_COMMENT:
case SCE_CAML_COMMENT1:
case SCE_CAML_COMMENT2:
case SCE_CAML_COMMENT3:
// we're IN a comment - does this start a NESTED comment?
if (sc.Match('(', '*'))
state2 = sc.state + 1, chToken = sc.currentPos,
sc.Forward(), sc.ch = ' ' /* (*)... */, nesting++;
// [try to] interpret as [additional] comment char
else if (sc.Match(')') && sc.chPrev == '*') {
if (nesting)
state2 = (sc.state & 0x0f) - 1, chToken = 0, nesting--;
else
state2 = SCE_CAML_DEFAULT;
chColor++;
// enable "magic" (read-only) comment AS REQUIRED
} else if (useMagic && sc.currentPos - chToken == 4
&& sc.Match('c') && sc.chPrev == 'r' && sc.GetRelative(-2) == '@')
sc.state |= 0x10; // (switch to read-only comment style)
break;
}
// handle state change and char coloring AS REQUIRED
if (state2 >= 0)
styler.ColourTo(chColor, sc.state), sc.ChangeState(state2);
// move to next char UNLESS re-scanning current char
if (advance)
sc.Forward();
}
// do any required terminal char coloring (JIC)
sc.Complete();
}
static
void FoldCamlDoc(
Sci_PositionU, Sci_Position,
int,
WordList *[],
Accessor &)
{
}
static const char * const camlWordListDesc[] = {
"Keywords", // primary Objective Caml keywords
"Keywords2", // "optional" keywords (typically from Pervasives)
"Keywords3", // "optional" keywords (typically typenames)
0
};
LexerModule lmCaml(SCLEX_CAML, ColouriseCamlDoc, "caml", FoldCamlDoc, camlWordListDesc);

View File

@ -0,0 +1,459 @@
// Scintilla source code edit control
/** @file LexCmake.cxx
** Lexer for Cmake
**/
// Copyright 2007 by Cristian Adam <cristian [dot] adam [at] gmx [dot] net>
// based on the NSIS lexer
// 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;
static bool isCmakeNumber(char ch)
{
return(ch >= '0' && ch <= '9');
}
static bool isCmakeChar(char ch)
{
return(ch == '.' ) || (ch == '_' ) || isCmakeNumber(ch) || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
}
static bool isCmakeLetter(char ch)
{
return(ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
}
static bool CmakeNextLineHasElse(Sci_PositionU start, Sci_PositionU end, Accessor &styler)
{
Sci_Position nNextLine = -1;
for ( Sci_PositionU i = start; i < end; i++ ) {
char cNext = styler.SafeGetCharAt( i );
if ( cNext == '\n' ) {
nNextLine = i+1;
break;
}
}
if ( nNextLine == -1 ) // We never foudn the next line...
return false;
for ( Sci_PositionU firstChar = nNextLine; firstChar < end; firstChar++ ) {
char cNext = styler.SafeGetCharAt( firstChar );
if ( cNext == ' ' )
continue;
if ( cNext == '\t' )
continue;
if ( styler.Match(firstChar, "ELSE") || styler.Match(firstChar, "else"))
return true;
break;
}
return false;
}
static int calculateFoldCmake(Sci_PositionU start, Sci_PositionU end, int foldlevel, Accessor &styler, bool bElse)
{
// If the word is too long, it is not what we are looking for
if ( end - start > 20 )
return foldlevel;
int newFoldlevel = foldlevel;
char s[20]; // The key word we are looking for has atmost 13 characters
for (unsigned int i = 0; i < end - start + 1 && i < 19; i++) {
s[i] = static_cast<char>( styler[ start + i ] );
s[i + 1] = '\0';
}
if ( CompareCaseInsensitive(s, "IF") == 0 || CompareCaseInsensitive(s, "WHILE") == 0
|| CompareCaseInsensitive(s, "MACRO") == 0 || CompareCaseInsensitive(s, "FOREACH") == 0
|| CompareCaseInsensitive(s, "FUNCTION") == 0)
newFoldlevel++;
else if ( CompareCaseInsensitive(s, "ENDIF") == 0 || CompareCaseInsensitive(s, "ENDWHILE") == 0
|| CompareCaseInsensitive(s, "ENDMACRO") == 0 || CompareCaseInsensitive(s, "ENDFOREACH") == 0
|| CompareCaseInsensitive(s, "ENDFUNCTION") == 0)
newFoldlevel--;
else if ( bElse && CompareCaseInsensitive(s, "ELSEIF") == 0 )
newFoldlevel++;
else if ( bElse && CompareCaseInsensitive(s, "ELSE") == 0 )
newFoldlevel++;
return newFoldlevel;
}
static int classifyWordCmake(Sci_PositionU start, Sci_PositionU end, WordList *keywordLists[], Accessor &styler )
{
char word[100] = {0};
char lowercaseWord[100] = {0};
WordList &Commands = *keywordLists[0];
WordList &Parameters = *keywordLists[1];
WordList &UserDefined = *keywordLists[2];
for (Sci_PositionU i = 0; i < end - start + 1 && i < 99; i++) {
word[i] = static_cast<char>( styler[ start + i ] );
lowercaseWord[i] = static_cast<char>(tolower(word[i]));
}
// Check for special words...
if ( CompareCaseInsensitive(word, "MACRO") == 0 || CompareCaseInsensitive(word, "ENDMACRO") == 0 )
return SCE_CMAKE_MACRODEF;
if ( CompareCaseInsensitive(word, "IF") == 0 || CompareCaseInsensitive(word, "ENDIF") == 0 )
return SCE_CMAKE_IFDEFINEDEF;
if ( CompareCaseInsensitive(word, "ELSEIF") == 0 || CompareCaseInsensitive(word, "ELSE") == 0 )
return SCE_CMAKE_IFDEFINEDEF;
if ( CompareCaseInsensitive(word, "WHILE") == 0 || CompareCaseInsensitive(word, "ENDWHILE") == 0)
return SCE_CMAKE_WHILEDEF;
if ( CompareCaseInsensitive(word, "FOREACH") == 0 || CompareCaseInsensitive(word, "ENDFOREACH") == 0)
return SCE_CMAKE_FOREACHDEF;
if ( Commands.InList(lowercaseWord) )
return SCE_CMAKE_COMMANDS;
if ( Parameters.InList(word) )
return SCE_CMAKE_PARAMETERS;
if ( UserDefined.InList(word) )
return SCE_CMAKE_USERDEFINED;
if ( strlen(word) > 3 ) {
if ( word[1] == '{' && word[strlen(word)-1] == '}' )
return SCE_CMAKE_VARIABLE;
}
// To check for numbers
if ( isCmakeNumber( word[0] ) ) {
bool bHasSimpleCmakeNumber = true;
for (unsigned int j = 1; j < end - start + 1 && j < 99; j++) {
if ( !isCmakeNumber( word[j] ) ) {
bHasSimpleCmakeNumber = false;
break;
}
}
if ( bHasSimpleCmakeNumber )
return SCE_CMAKE_NUMBER;
}
return SCE_CMAKE_DEFAULT;
}
static void ColouriseCmakeDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *keywordLists[], Accessor &styler)
{
int state = SCE_CMAKE_DEFAULT;
if ( startPos > 0 )
state = styler.StyleAt(startPos-1); // Use the style from the previous line, usually default, but could be commentbox
styler.StartAt( startPos );
styler.GetLine( startPos );
Sci_PositionU nLengthDoc = startPos + length;
styler.StartSegment( startPos );
char cCurrChar;
bool bVarInString = false;
bool bClassicVarInString = false;
Sci_PositionU i;
for ( i = startPos; i < nLengthDoc; i++ ) {
cCurrChar = styler.SafeGetCharAt( i );
char cNextChar = styler.SafeGetCharAt(i+1);
switch (state) {
case SCE_CMAKE_DEFAULT:
if ( cCurrChar == '#' ) { // we have a comment line
styler.ColourTo(i-1, state );
state = SCE_CMAKE_COMMENT;
break;
}
if ( cCurrChar == '"' ) {
styler.ColourTo(i-1, state );
state = SCE_CMAKE_STRINGDQ;
bVarInString = false;
bClassicVarInString = false;
break;
}
if ( cCurrChar == '\'' ) {
styler.ColourTo(i-1, state );
state = SCE_CMAKE_STRINGRQ;
bVarInString = false;
bClassicVarInString = false;
break;
}
if ( cCurrChar == '`' ) {
styler.ColourTo(i-1, state );
state = SCE_CMAKE_STRINGLQ;
bVarInString = false;
bClassicVarInString = false;
break;
}
// CMake Variable
if ( cCurrChar == '$' || isCmakeChar(cCurrChar)) {
styler.ColourTo(i-1,state);
state = SCE_CMAKE_VARIABLE;
// If it is a number, we must check and set style here first...
if ( isCmakeNumber(cCurrChar) && (cNextChar == '\t' || cNextChar == ' ' || cNextChar == '\r' || cNextChar == '\n' ) )
styler.ColourTo( i, SCE_CMAKE_NUMBER);
break;
}
break;
case SCE_CMAKE_COMMENT:
if ( cCurrChar == '\n' || cCurrChar == '\r' ) {
if ( styler.SafeGetCharAt(i-1) == '\\' ) {
styler.ColourTo(i-2,state);
styler.ColourTo(i-1,SCE_CMAKE_DEFAULT);
}
else {
styler.ColourTo(i-1,state);
state = SCE_CMAKE_DEFAULT;
}
}
break;
case SCE_CMAKE_STRINGDQ:
case SCE_CMAKE_STRINGLQ:
case SCE_CMAKE_STRINGRQ:
if ( styler.SafeGetCharAt(i-1) == '\\' && styler.SafeGetCharAt(i-2) == '$' )
break; // Ignore the next character, even if it is a quote of some sort
if ( cCurrChar == '"' && state == SCE_CMAKE_STRINGDQ ) {
styler.ColourTo(i,state);
state = SCE_CMAKE_DEFAULT;
break;
}
if ( cCurrChar == '`' && state == SCE_CMAKE_STRINGLQ ) {
styler.ColourTo(i,state);
state = SCE_CMAKE_DEFAULT;
break;
}
if ( cCurrChar == '\'' && state == SCE_CMAKE_STRINGRQ ) {
styler.ColourTo(i,state);
state = SCE_CMAKE_DEFAULT;
break;
}
if ( cNextChar == '\r' || cNextChar == '\n' ) {
Sci_Position nCurLine = styler.GetLine(i+1);
Sci_Position nBack = i;
// We need to check if the previous line has a \ in it...
bool bNextLine = false;
while ( nBack > 0 ) {
if ( styler.GetLine(nBack) != nCurLine )
break;
char cTemp = styler.SafeGetCharAt(nBack, 'a'); // Letter 'a' is safe here
if ( cTemp == '\\' ) {
bNextLine = true;
break;
}
if ( cTemp != '\r' && cTemp != '\n' && cTemp != '\t' && cTemp != ' ' )
break;
nBack--;
}
if ( bNextLine ) {
styler.ColourTo(i+1,state);
}
if ( bNextLine == false ) {
styler.ColourTo(i,state);
state = SCE_CMAKE_DEFAULT;
}
}
break;
case SCE_CMAKE_VARIABLE:
// CMake Variable:
if ( cCurrChar == '$' )
state = SCE_CMAKE_DEFAULT;
else if ( cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' ) )
state = SCE_CMAKE_DEFAULT;
else if ( (isCmakeChar(cCurrChar) && !isCmakeChar( cNextChar) && cNextChar != '}') || cCurrChar == '}' ) {
state = classifyWordCmake( styler.GetStartSegment(), i, keywordLists, styler );
styler.ColourTo( i, state);
state = SCE_CMAKE_DEFAULT;
}
else if ( !isCmakeChar( cCurrChar ) && cCurrChar != '{' && cCurrChar != '}' ) {
if ( classifyWordCmake( styler.GetStartSegment(), i-1, keywordLists, styler) == SCE_CMAKE_NUMBER )
styler.ColourTo( i-1, SCE_CMAKE_NUMBER );
state = SCE_CMAKE_DEFAULT;
if ( cCurrChar == '"' ) {
state = SCE_CMAKE_STRINGDQ;
bVarInString = false;
bClassicVarInString = false;
}
else if ( cCurrChar == '`' ) {
state = SCE_CMAKE_STRINGLQ;
bVarInString = false;
bClassicVarInString = false;
}
else if ( cCurrChar == '\'' ) {
state = SCE_CMAKE_STRINGRQ;
bVarInString = false;
bClassicVarInString = false;
}
else if ( cCurrChar == '#' ) {
state = SCE_CMAKE_COMMENT;
}
}
break;
}
if ( state == SCE_CMAKE_STRINGDQ || state == SCE_CMAKE_STRINGLQ || state == SCE_CMAKE_STRINGRQ ) {
bool bIngoreNextDollarSign = false;
if ( bVarInString && cCurrChar == '$' ) {
bVarInString = false;
bIngoreNextDollarSign = true;
}
else if ( bVarInString && cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' || cNextChar == '"' || cNextChar == '`' || cNextChar == '\'' ) ) {
styler.ColourTo( i+1, SCE_CMAKE_STRINGVAR);
bVarInString = false;
bIngoreNextDollarSign = false;
}
else if ( bVarInString && !isCmakeChar(cNextChar) ) {
int nWordState = classifyWordCmake( styler.GetStartSegment(), i, keywordLists, styler);
if ( nWordState == SCE_CMAKE_VARIABLE )
styler.ColourTo( i, SCE_CMAKE_STRINGVAR);
bVarInString = false;
}
// Covers "${TEST}..."
else if ( bClassicVarInString && cNextChar == '}' ) {
styler.ColourTo( i+1, SCE_CMAKE_STRINGVAR);
bClassicVarInString = false;
}
// Start of var in string
if ( !bIngoreNextDollarSign && cCurrChar == '$' && cNextChar == '{' ) {
styler.ColourTo( i-1, state);
bClassicVarInString = true;
bVarInString = false;
}
else if ( !bIngoreNextDollarSign && cCurrChar == '$' ) {
styler.ColourTo( i-1, state);
bVarInString = true;
bClassicVarInString = false;
}
}
}
// Colourise remaining document
styler.ColourTo(nLengthDoc-1,state);
}
static void FoldCmakeDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler)
{
// No folding enabled, no reason to continue...
if ( styler.GetPropertyInt("fold") == 0 )
return;
bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) == 1;
Sci_Position lineCurrent = styler.GetLine(startPos);
Sci_PositionU safeStartPos = styler.LineStart( lineCurrent );
bool bArg1 = true;
Sci_Position nWordStart = -1;
int levelCurrent = SC_FOLDLEVELBASE;
if (lineCurrent > 0)
levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
int levelNext = levelCurrent;
for (Sci_PositionU i = safeStartPos; i < startPos + length; i++) {
char chCurr = styler.SafeGetCharAt(i);
if ( bArg1 ) {
if ( nWordStart == -1 && (isCmakeLetter(chCurr)) ) {
nWordStart = i;
}
else if ( isCmakeLetter(chCurr) == false && nWordStart > -1 ) {
int newLevel = calculateFoldCmake( nWordStart, i-1, levelNext, styler, foldAtElse);
if ( newLevel == levelNext ) {
if ( foldAtElse ) {
if ( CmakeNextLineHasElse(i, startPos + length, styler) )
levelNext--;
}
}
else
levelNext = newLevel;
bArg1 = false;
}
}
if ( chCurr == '\n' ) {
if ( bArg1 && foldAtElse) {
if ( CmakeNextLineHasElse(i, startPos + length, styler) )
levelNext--;
}
// If we are on a new line...
int levelUse = levelCurrent;
int lev = levelUse | levelNext << 16;
if (levelUse < levelNext )
lev |= SC_FOLDLEVELHEADERFLAG;
if (lev != styler.LevelAt(lineCurrent))
styler.SetLevel(lineCurrent, lev);
lineCurrent++;
levelCurrent = levelNext;
bArg1 = true; // New line, lets look at first argument again
nWordStart = -1;
}
}
int levelUse = levelCurrent;
int lev = levelUse | levelNext << 16;
if (levelUse < levelNext)
lev |= SC_FOLDLEVELHEADERFLAG;
if (lev != styler.LevelAt(lineCurrent))
styler.SetLevel(lineCurrent, lev);
}
static const char * const cmakeWordLists[] = {
"Commands",
"Parameters",
"UserDefined",
0,
0,};
LexerModule lmCmake(SCLEX_CMAKE, ColouriseCmakeDoc, "cmake", FoldCmakeDoc, cmakeWordLists);

View File

@ -0,0 +1,494 @@
// Scintilla source code edit control
/** @file LexCoffeeScript.cxx
** Lexer for CoffeeScript.
**/
// Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org>
// Based on the Scintilla C++ Lexer
// Written by Eric Promislow <ericp@activestate.com> in 2011 for the Komodo IDE
// 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 <algorithm>
#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;
static bool IsSpaceEquiv(int state) {
return (state == SCE_COFFEESCRIPT_DEFAULT
|| state == SCE_COFFEESCRIPT_COMMENTLINE
|| state == SCE_COFFEESCRIPT_COMMENTBLOCK
|| state == SCE_COFFEESCRIPT_VERBOSE_REGEX
|| state == SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT
|| state == SCE_COFFEESCRIPT_WORD
|| state == SCE_COFFEESCRIPT_REGEX);
}
// Store the current lexer state and brace count prior to starting a new
// `#{}` interpolation level.
// Based on LexRuby.cxx.
static void enterInnerExpression(int *p_inner_string_types,
int *p_inner_expn_brace_counts,
int& inner_string_count,
int state,
int& brace_counts
) {
p_inner_string_types[inner_string_count] = state;
p_inner_expn_brace_counts[inner_string_count] = brace_counts;
brace_counts = 0;
++inner_string_count;
}
// Restore the lexer state and brace count for the previous `#{}` interpolation
// level upon returning to it.
// Note the previous lexer state is the return value and needs to be restored
// manually by the StyleContext.
// Based on LexRuby.cxx.
static int exitInnerExpression(int *p_inner_string_types,
int *p_inner_expn_brace_counts,
int& inner_string_count,
int& brace_counts
) {
--inner_string_count;
brace_counts = p_inner_expn_brace_counts[inner_string_count];
return p_inner_string_types[inner_string_count];
}
// Preconditions: sc.currentPos points to a character after '+' or '-'.
// The test for pos reaching 0 should be redundant,
// and is in only for safety measures.
// Limitation: this code will give the incorrect answer for code like
// a = b+++/ptn/...
// Putting a space between the '++' post-inc operator and the '+' binary op
// fixes this, and is highly recommended for readability anyway.
static bool FollowsPostfixOperator(StyleContext &sc, Accessor &styler) {
Sci_Position pos = (Sci_Position) sc.currentPos;
while (--pos > 0) {
char ch = styler[pos];
if (ch == '+' || ch == '-') {
return styler[pos - 1] == ch;
}
}
return false;
}
static bool followsKeyword(StyleContext &sc, Accessor &styler) {
Sci_Position pos = (Sci_Position) sc.currentPos;
Sci_Position currentLine = styler.GetLine(pos);
Sci_Position lineStartPos = styler.LineStart(currentLine);
while (--pos > lineStartPos) {
char ch = styler.SafeGetCharAt(pos);
if (ch != ' ' && ch != '\t') {
break;
}
}
styler.Flush();
return styler.StyleAt(pos) == SCE_COFFEESCRIPT_WORD;
}
#if defined(__clang__)
#if __has_warning("-Wunused-but-set-variable")
// Disable warning for visibleChars
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#endif
#endif
static void ColouriseCoffeeScriptDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
WordList &keywords = *keywordlists[0];
WordList &keywords2 = *keywordlists[1];
WordList &keywords4 = *keywordlists[3];
CharacterSet setOKBeforeRE(CharacterSet::setNone, "([{=,:;!%^&*|?~+-");
CharacterSet setCouldBePostOp(CharacterSet::setNone, "+-");
CharacterSet setWordStart(CharacterSet::setAlpha, "_$@", 0x80, true);
CharacterSet setWord(CharacterSet::setAlphaNum, "._$", 0x80, true);
int chPrevNonWhite = ' ';
int visibleChars = 0;
// String/Regex interpolation variables, based on LexRuby.cxx.
// In most cases a value of 2 should be ample for the code the user is
// likely to enter. For example,
// "Filling the #{container} with #{liquid}..."
// from the CoffeeScript homepage nests to a level of 2
// If the user actually hits a 6th occurrence of '#{' in a double-quoted
// string (including regexes), it will stay as a string. The problem with
// this is that quotes might flip, a 7th '#{' will look like a comment,
// and code-folding might be wrong.
#define INNER_STRINGS_MAX_COUNT 5
// These vars track our instances of "...#{,,,'..#{,,,}...',,,}..."
int inner_string_types[INNER_STRINGS_MAX_COUNT];
// Track # braces when we push a new #{ thing
int inner_expn_brace_counts[INNER_STRINGS_MAX_COUNT];
int inner_string_count = 0;
int brace_counts = 0; // Number of #{ ... } things within an expression
for (int i = 0; i < INNER_STRINGS_MAX_COUNT; i++) {
inner_string_types[i] = 0;
inner_expn_brace_counts[i] = 0;
}
// look back to set chPrevNonWhite properly for better regex colouring
Sci_Position endPos = startPos + length;
if (startPos > 0 && IsSpaceEquiv(initStyle)) {
Sci_PositionU back = startPos;
styler.Flush();
while (back > 0 && IsSpaceEquiv(styler.StyleAt(--back)))
;
if (styler.StyleAt(back) == SCE_COFFEESCRIPT_OPERATOR) {
chPrevNonWhite = styler.SafeGetCharAt(back);
}
if (startPos != back) {
initStyle = styler.StyleAt(back);
if (IsSpaceEquiv(initStyle)) {
initStyle = SCE_COFFEESCRIPT_DEFAULT;
}
}
startPos = back;
}
StyleContext sc(startPos, endPos - startPos, initStyle, styler);
for (; sc.More();) {
if (sc.atLineStart) {
// Reset states to beginning of colourise so no surprises
// if different sets of lines lexed.
visibleChars = 0;
}
// Determine if the current state should terminate.
switch (sc.state) {
case SCE_COFFEESCRIPT_OPERATOR:
sc.SetState(SCE_COFFEESCRIPT_DEFAULT);
break;
case SCE_COFFEESCRIPT_NUMBER:
// We accept almost anything because of hex. and number suffixes
if (!setWord.Contains(sc.ch) || sc.Match('.', '.')) {
sc.SetState(SCE_COFFEESCRIPT_DEFAULT);
}
break;
case SCE_COFFEESCRIPT_IDENTIFIER:
if (!setWord.Contains(sc.ch) || (sc.ch == '.') || (sc.ch == '$')) {
char s[1000];
sc.GetCurrent(s, sizeof(s));
if (keywords.InList(s)) {
sc.ChangeState(SCE_COFFEESCRIPT_WORD);
} else if (keywords2.InList(s)) {
sc.ChangeState(SCE_COFFEESCRIPT_WORD2);
} else if (keywords4.InList(s)) {
sc.ChangeState(SCE_COFFEESCRIPT_GLOBALCLASS);
} else if (sc.LengthCurrent() > 0 && s[0] == '@') {
sc.ChangeState(SCE_COFFEESCRIPT_INSTANCEPROPERTY);
}
sc.SetState(SCE_COFFEESCRIPT_DEFAULT);
}
break;
case SCE_COFFEESCRIPT_WORD:
case SCE_COFFEESCRIPT_WORD2:
case SCE_COFFEESCRIPT_GLOBALCLASS:
case SCE_COFFEESCRIPT_INSTANCEPROPERTY:
if (!setWord.Contains(sc.ch)) {
sc.SetState(SCE_COFFEESCRIPT_DEFAULT);
}
break;
case SCE_COFFEESCRIPT_COMMENTLINE:
if (sc.atLineStart) {
sc.SetState(SCE_COFFEESCRIPT_DEFAULT);
}
break;
case SCE_COFFEESCRIPT_STRING:
if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_COFFEESCRIPT_DEFAULT);
} else if (sc.ch == '#' && sc.chNext == '{' && inner_string_count < INNER_STRINGS_MAX_COUNT) {
// process interpolated code #{ ... }
enterInnerExpression(inner_string_types,
inner_expn_brace_counts,
inner_string_count,
sc.state,
brace_counts);
sc.SetState(SCE_COFFEESCRIPT_OPERATOR);
sc.ForwardSetState(SCE_COFFEESCRIPT_DEFAULT);
}
break;
case SCE_COFFEESCRIPT_CHARACTER:
if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\'') {
sc.ForwardSetState(SCE_COFFEESCRIPT_DEFAULT);
}
break;
case SCE_COFFEESCRIPT_REGEX:
if (sc.atLineStart) {
sc.SetState(SCE_COFFEESCRIPT_DEFAULT);
} else if (sc.ch == '/') {
sc.Forward();
while ((sc.ch < 0x80) && islower(sc.ch))
sc.Forward(); // gobble regex flags
sc.SetState(SCE_COFFEESCRIPT_DEFAULT);
} else if (sc.ch == '\\') {
// Gobble up the quoted character
if (sc.chNext == '\\' || sc.chNext == '/') {
sc.Forward();
}
}
break;
case SCE_COFFEESCRIPT_STRINGEOL:
if (sc.atLineStart) {
sc.SetState(SCE_COFFEESCRIPT_DEFAULT);
}
break;
case SCE_COFFEESCRIPT_COMMENTBLOCK:
if (sc.Match("###")) {
sc.Forward();
sc.Forward();
sc.ForwardSetState(SCE_COFFEESCRIPT_DEFAULT);
} else if (sc.ch == '\\') {
sc.Forward();
}
break;
case SCE_COFFEESCRIPT_VERBOSE_REGEX:
if (sc.Match("///")) {
sc.Forward();
sc.Forward();
sc.ForwardSetState(SCE_COFFEESCRIPT_DEFAULT);
} else if (sc.Match('#')) {
sc.SetState(SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT);
} else if (sc.ch == '\\') {
sc.Forward();
}
break;
case SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT:
if (sc.atLineStart) {
sc.SetState(SCE_COFFEESCRIPT_VERBOSE_REGEX);
}
break;
}
// Determine if a new state should be entered.
if (sc.state == SCE_COFFEESCRIPT_DEFAULT) {
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_COFFEESCRIPT_NUMBER);
} else if (setWordStart.Contains(sc.ch)) {
sc.SetState(SCE_COFFEESCRIPT_IDENTIFIER);
} else if (sc.Match("///")) {
sc.SetState(SCE_COFFEESCRIPT_VERBOSE_REGEX);
sc.Forward();
sc.Forward();
} else if (sc.ch == '/'
&& (setOKBeforeRE.Contains(chPrevNonWhite)
|| followsKeyword(sc, styler))
&& (!setCouldBePostOp.Contains(chPrevNonWhite)
|| !FollowsPostfixOperator(sc, styler))) {
sc.SetState(SCE_COFFEESCRIPT_REGEX); // JavaScript's RegEx
} else if (sc.ch == '\"') {
sc.SetState(SCE_COFFEESCRIPT_STRING);
} else if (sc.ch == '\'') {
sc.SetState(SCE_COFFEESCRIPT_CHARACTER);
} else if (sc.ch == '#') {
if (sc.Match("###")) {
sc.SetState(SCE_COFFEESCRIPT_COMMENTBLOCK);
sc.Forward();
sc.Forward();
} else {
sc.SetState(SCE_COFFEESCRIPT_COMMENTLINE);
}
} else if (isoperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_COFFEESCRIPT_OPERATOR);
// Handle '..' and '...' operators correctly.
if (sc.ch == '.') {
for (int i = 0; i < 2 && sc.chNext == '.'; i++, sc.Forward()) ;
} else if (sc.ch == '{') {
++brace_counts;
} else if (sc.ch == '}' && --brace_counts <= 0 && inner_string_count > 0) {
// Return to previous state before #{ ... }
sc.ForwardSetState(exitInnerExpression(inner_string_types,
inner_expn_brace_counts,
inner_string_count,
brace_counts));
continue; // skip sc.Forward() at loop end
}
}
}
if (!IsASpace(sc.ch) && !IsSpaceEquiv(sc.state)) {
chPrevNonWhite = sc.ch;
visibleChars++;
}
sc.Forward();
}
sc.Complete();
}
static bool IsCommentLine(Sci_Position line, Accessor &styler) {
Sci_Position pos = styler.LineStart(line);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eol_pos; i++) {
char ch = styler[i];
if (ch == '#')
return true;
else if (ch != ' ' && ch != '\t')
return false;
}
return false;
}
static void FoldCoffeeScriptDoc(Sci_PositionU startPos, Sci_Position length, int,
WordList *[], Accessor &styler) {
// A simplified version of FoldPyDoc
const Sci_Position maxPos = startPos + length;
const Sci_Position maxLines = styler.GetLine(maxPos - 1); // Requested last line
const Sci_Position docLines = styler.GetLine(styler.Length() - 1); // Available last line
// property fold.coffeescript.comment
// Set to 1 to allow folding of comment blocks in CoffeeScript.
const bool foldComment = styler.GetPropertyInt("fold.coffeescript.comment") != 0;
const bool foldCompact = styler.GetPropertyInt("fold.compact") != 0;
// Backtrack to previous non-blank line so we can determine indent level
// for any white space lines
// and so we can fix any preceding fold level (which is why we go back
// at least one line in all cases)
int spaceFlags = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL);
while (lineCurrent > 0) {
lineCurrent--;
indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL);
if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)
&& !IsCommentLine(lineCurrent, styler))
break;
}
int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;
// Set up initial loop state
int prevComment = 0;
if (lineCurrent >= 1)
prevComment = foldComment && IsCommentLine(lineCurrent - 1, styler);
// Process all characters to end of requested range
// or comment that hangs over the end of the range. Cap processing in all cases
// to end of document (in case of comment at end).
while ((lineCurrent <= docLines) && ((lineCurrent <= maxLines) || prevComment)) {
// Gather info
int lev = indentCurrent;
Sci_Position lineNext = lineCurrent + 1;
int indentNext = indentCurrent;
if (lineNext <= docLines) {
// Information about next line is only available if not at end of document
indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL);
}
const int comment = foldComment && IsCommentLine(lineCurrent, styler);
const int comment_start = (comment && !prevComment && (lineNext <= docLines) &&
IsCommentLine(lineNext, styler) && (lev > SC_FOLDLEVELBASE));
const int comment_continue = (comment && prevComment);
if (!comment)
indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;
if (indentNext & SC_FOLDLEVELWHITEFLAG)
indentNext = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel;
if (comment_start) {
// Place fold point at start of a block of comments
lev |= SC_FOLDLEVELHEADERFLAG;
} else if (comment_continue) {
// Add level to rest of lines in the block
lev = lev + 1;
}
// Skip past any blank lines for next indent level info; we skip also
// comments (all comments, not just those starting in column 0)
// which effectively folds them into surrounding code rather
// than screwing up folding.
while ((lineNext < docLines) &&
((indentNext & SC_FOLDLEVELWHITEFLAG) ||
(lineNext <= docLines && IsCommentLine(lineNext, styler)))) {
lineNext++;
indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL);
}
const int levelAfterComments = indentNext & SC_FOLDLEVELNUMBERMASK;
const int levelBeforeComments = std::max(indentCurrentLevel,levelAfterComments);
// Now set all the indent levels on the lines we skipped
// Do this from end to start. Once we encounter one line
// which is indented more than the line after the end of
// the comment-block, use the level of the block before
Sci_Position skipLine = lineNext;
int skipLevel = levelAfterComments;
while (--skipLine > lineCurrent) {
int skipLineIndent = styler.IndentAmount(skipLine, &spaceFlags, NULL);
if (foldCompact) {
if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments)
skipLevel = levelBeforeComments;
int whiteFlag = skipLineIndent & SC_FOLDLEVELWHITEFLAG;
styler.SetLevel(skipLine, skipLevel | whiteFlag);
} else {
if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments &&
!(skipLineIndent & SC_FOLDLEVELWHITEFLAG) &&
!IsCommentLine(skipLine, styler))
skipLevel = levelBeforeComments;
styler.SetLevel(skipLine, skipLevel);
}
}
// Set fold header on non-comment line
if (!comment && !(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK))
lev |= SC_FOLDLEVELHEADERFLAG;
}
// Keep track of block comment state of previous line
prevComment = comment_start || comment_continue;
// Set fold level for this line and move to next line
styler.SetLevel(lineCurrent, lev);
indentCurrent = indentNext;
lineCurrent = lineNext;
}
}
static const char *const csWordLists[] = {
"Keywords",
"Secondary keywords",
"Unused",
"Global classes",
0,
};
LexerModule lmCoffeeScript(SCLEX_COFFEESCRIPT, ColouriseCoffeeScriptDoc, "coffeescript", FoldCoffeeScriptDoc, csWordLists);

View File

@ -0,0 +1,193 @@
// Scintilla source code edit control
/** @file LexConf.cxx
** Lexer for Apache Configuration Files.
**
** First working version contributed by Ahmad Zawawi <ahmad.zawawi@gmail.com> on October 28, 2000.
** i created this lexer because i needed something pretty when dealing
** when Apache Configuration files...
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// 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;
static void ColouriseConfDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *keywordLists[], Accessor &styler)
{
int state = SCE_CONF_DEFAULT;
char chNext = styler[startPos];
Sci_Position lengthDoc = startPos + length;
// create a buffer large enough to take the largest chunk...
char *buffer = new char[length+1];
Sci_Position bufferCount = 0;
// this assumes that we have 2 keyword list in conf.properties
WordList &directives = *keywordLists[0];
WordList &params = *keywordLists[1];
// go through all provided text segment
// using the hand-written state machine shown below
styler.StartAt(startPos);
styler.StartSegment(startPos);
for (Sci_Position i = startPos; i < lengthDoc; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if (styler.IsLeadByte(ch)) {
chNext = styler.SafeGetCharAt(i + 2);
i++;
continue;
}
switch(state) {
case SCE_CONF_DEFAULT:
if( ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ') {
// whitespace is simply ignored here...
styler.ColourTo(i,SCE_CONF_DEFAULT);
break;
} else if( ch == '#' ) {
// signals the start of a comment...
state = SCE_CONF_COMMENT;
styler.ColourTo(i,SCE_CONF_COMMENT);
} else if( ch == '.' /*|| ch == '/'*/) {
// signals the start of a file...
state = SCE_CONF_EXTENSION;
styler.ColourTo(i,SCE_CONF_EXTENSION);
} else if( ch == '"') {
state = SCE_CONF_STRING;
styler.ColourTo(i,SCE_CONF_STRING);
} else if( IsASCII(ch) && ispunct(ch) ) {
// signals an operator...
// no state jump necessary for this
// simple case...
styler.ColourTo(i,SCE_CONF_OPERATOR);
} else if( IsASCII(ch) && isalpha(ch) ) {
// signals the start of an identifier
bufferCount = 0;
buffer[bufferCount++] = static_cast<char>(tolower(ch));
state = SCE_CONF_IDENTIFIER;
} else if( IsASCII(ch) && isdigit(ch) ) {
// signals the start of a number
bufferCount = 0;
buffer[bufferCount++] = ch;
//styler.ColourTo(i,SCE_CONF_NUMBER);
state = SCE_CONF_NUMBER;
} else {
// style it the default style..
styler.ColourTo(i,SCE_CONF_DEFAULT);
}
break;
case SCE_CONF_COMMENT:
// if we find a newline here,
// we simply go to default state
// else continue to work on it...
if( ch == '\n' || ch == '\r' ) {
state = SCE_CONF_DEFAULT;
} else {
styler.ColourTo(i,SCE_CONF_COMMENT);
}
break;
case SCE_CONF_EXTENSION:
// if we find a non-alphanumeric char,
// we simply go to default state
// else we're still dealing with an extension...
if( (IsASCII(ch) && isalnum(ch)) || (ch == '_') ||
(ch == '-') || (ch == '$') ||
(ch == '/') || (ch == '.') || (ch == '*') )
{
styler.ColourTo(i,SCE_CONF_EXTENSION);
} else {
state = SCE_CONF_DEFAULT;
chNext = styler[i--];
}
break;
case SCE_CONF_STRING:
// if we find the end of a string char, we simply go to default state
// else we're still dealing with an string...
if( (ch == '"' && styler.SafeGetCharAt(i-1)!='\\') || (ch == '\n') || (ch == '\r') ) {
state = SCE_CONF_DEFAULT;
}
styler.ColourTo(i,SCE_CONF_STRING);
break;
case SCE_CONF_IDENTIFIER:
// stay in CONF_IDENTIFIER state until we find a non-alphanumeric
if( (IsASCII(ch) && isalnum(ch)) || (ch == '_') || (ch == '-') || (ch == '/') || (ch == '$') || (ch == '.') || (ch == '*')) {
buffer[bufferCount++] = static_cast<char>(tolower(ch));
} else {
state = SCE_CONF_DEFAULT;
buffer[bufferCount] = '\0';
// check if the buffer contains a keyword, and highlight it if it is a keyword...
if(directives.InList(buffer)) {
styler.ColourTo(i-1,SCE_CONF_DIRECTIVE );
} else if(params.InList(buffer)) {
styler.ColourTo(i-1,SCE_CONF_PARAMETER );
} else if(strchr(buffer,'/') || strchr(buffer,'.')) {
styler.ColourTo(i-1,SCE_CONF_EXTENSION);
} else {
styler.ColourTo(i-1,SCE_CONF_DEFAULT);
}
// push back the faulty character
chNext = styler[i--];
}
break;
case SCE_CONF_NUMBER:
// stay in CONF_NUMBER state until we find a non-numeric
if( (IsASCII(ch) && isdigit(ch)) || ch == '.') {
buffer[bufferCount++] = ch;
} else {
state = SCE_CONF_DEFAULT;
buffer[bufferCount] = '\0';
// Colourize here...
if( strchr(buffer,'.') ) {
// it is an IP address...
styler.ColourTo(i-1,SCE_CONF_IP);
} else {
// normal number
styler.ColourTo(i-1,SCE_CONF_NUMBER);
}
// push back a character
chNext = styler[i--];
}
break;
}
}
delete []buffer;
}
static const char * const confWordListDesc[] = {
"Directives",
"Parameters",
0
};
LexerModule lmConf(SCLEX_CONF, ColouriseConfDoc, "conf", 0, confWordListDesc);

View File

@ -0,0 +1,227 @@
// Scintilla source code edit control
/** @file LexCrontab.cxx
** Lexer to use with extended crontab files used by a powerful
** Windows scheduler/event monitor/automation manager nnCron.
** (http://nemtsev.eserv.ru/)
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// 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;
static void ColouriseNncrontabDoc(Sci_PositionU startPos, Sci_Position length, int, WordList
*keywordLists[], Accessor &styler)
{
int state = SCE_NNCRONTAB_DEFAULT;
char chNext = styler[startPos];
Sci_Position lengthDoc = startPos + length;
// create a buffer large enough to take the largest chunk...
char *buffer = new char[length+1];
Sci_Position bufferCount = 0;
// used when highliting environment variables inside quoted string:
bool insideString = false;
// this assumes that we have 3 keyword list in conf.properties
WordList &section = *keywordLists[0];
WordList &keyword = *keywordLists[1];
WordList &modifier = *keywordLists[2];
// go through all provided text segment
// using the hand-written state machine shown below
styler.StartAt(startPos);
styler.StartSegment(startPos);
for (Sci_Position i = startPos; i < lengthDoc; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if (styler.IsLeadByte(ch)) {
chNext = styler.SafeGetCharAt(i + 2);
i++;
continue;
}
switch(state) {
case SCE_NNCRONTAB_DEFAULT:
if( ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ') {
// whitespace is simply ignored here...
styler.ColourTo(i,SCE_NNCRONTAB_DEFAULT);
break;
} else if( ch == '#' && styler.SafeGetCharAt(i+1) == '(') {
// signals the start of a task...
state = SCE_NNCRONTAB_TASK;
styler.ColourTo(i,SCE_NNCRONTAB_TASK);
}
else if( ch == '\\' && (styler.SafeGetCharAt(i+1) == ' ' ||
styler.SafeGetCharAt(i+1) == '\t')) {
// signals the start of an extended comment...
state = SCE_NNCRONTAB_COMMENT;
styler.ColourTo(i,SCE_NNCRONTAB_COMMENT);
} else if( ch == '#' ) {
// signals the start of a plain comment...
state = SCE_NNCRONTAB_COMMENT;
styler.ColourTo(i,SCE_NNCRONTAB_COMMENT);
} else if( ch == ')' && styler.SafeGetCharAt(i+1) == '#') {
// signals the end of a task...
state = SCE_NNCRONTAB_TASK;
styler.ColourTo(i,SCE_NNCRONTAB_TASK);
} else if( ch == '"') {
state = SCE_NNCRONTAB_STRING;
styler.ColourTo(i,SCE_NNCRONTAB_STRING);
} else if( ch == '%') {
// signals environment variables
state = SCE_NNCRONTAB_ENVIRONMENT;
styler.ColourTo(i,SCE_NNCRONTAB_ENVIRONMENT);
} else if( ch == '<' && styler.SafeGetCharAt(i+1) == '%') {
// signals environment variables
state = SCE_NNCRONTAB_ENVIRONMENT;
styler.ColourTo(i,SCE_NNCRONTAB_ENVIRONMENT);
} else if( ch == '*' ) {
// signals an asterisk
// no state jump necessary for this simple case...
styler.ColourTo(i,SCE_NNCRONTAB_ASTERISK);
} else if( (IsASCII(ch) && isalpha(ch)) || ch == '<' ) {
// signals the start of an identifier
bufferCount = 0;
buffer[bufferCount++] = ch;
state = SCE_NNCRONTAB_IDENTIFIER;
} else if( IsASCII(ch) && isdigit(ch) ) {
// signals the start of a number
bufferCount = 0;
buffer[bufferCount++] = ch;
state = SCE_NNCRONTAB_NUMBER;
} else {
// style it the default style..
styler.ColourTo(i,SCE_NNCRONTAB_DEFAULT);
}
break;
case SCE_NNCRONTAB_COMMENT:
// if we find a newline here,
// we simply go to default state
// else continue to work on it...
if( ch == '\n' || ch == '\r' ) {
state = SCE_NNCRONTAB_DEFAULT;
} else {
styler.ColourTo(i,SCE_NNCRONTAB_COMMENT);
}
break;
case SCE_NNCRONTAB_TASK:
// if we find a newline here,
// we simply go to default state
// else continue to work on it...
if( ch == '\n' || ch == '\r' ) {
state = SCE_NNCRONTAB_DEFAULT;
} else {
styler.ColourTo(i,SCE_NNCRONTAB_TASK);
}
break;
case SCE_NNCRONTAB_STRING:
if( ch == '%' ) {
state = SCE_NNCRONTAB_ENVIRONMENT;
insideString = true;
styler.ColourTo(i-1,SCE_NNCRONTAB_STRING);
break;
}
// if we find the end of a string char, we simply go to default state
// else we're still dealing with an string...
if( (ch == '"' && styler.SafeGetCharAt(i-1)!='\\') ||
(ch == '\n') || (ch == '\r') ) {
state = SCE_NNCRONTAB_DEFAULT;
}
styler.ColourTo(i,SCE_NNCRONTAB_STRING);
break;
case SCE_NNCRONTAB_ENVIRONMENT:
// if we find the end of a string char, we simply go to default state
// else we're still dealing with an string...
if( ch == '%' && insideString ) {
state = SCE_NNCRONTAB_STRING;
insideString = false;
break;
}
if( (ch == '%' && styler.SafeGetCharAt(i-1)!='\\')
|| (ch == '\n') || (ch == '\r') || (ch == '>') ) {
state = SCE_NNCRONTAB_DEFAULT;
styler.ColourTo(i,SCE_NNCRONTAB_ENVIRONMENT);
break;
}
styler.ColourTo(i+1,SCE_NNCRONTAB_ENVIRONMENT);
break;
case SCE_NNCRONTAB_IDENTIFIER:
// stay in CONF_IDENTIFIER state until we find a non-alphanumeric
if( (IsASCII(ch) && isalnum(ch)) || (ch == '_') || (ch == '-') || (ch == '/') ||
(ch == '$') || (ch == '.') || (ch == '<') || (ch == '>') ||
(ch == '@') ) {
buffer[bufferCount++] = ch;
} else {
state = SCE_NNCRONTAB_DEFAULT;
buffer[bufferCount] = '\0';
// check if the buffer contains a keyword,
// and highlight it if it is a keyword...
if(section.InList(buffer)) {
styler.ColourTo(i,SCE_NNCRONTAB_SECTION );
} else if(keyword.InList(buffer)) {
styler.ColourTo(i-1,SCE_NNCRONTAB_KEYWORD );
} // else if(strchr(buffer,'/') || strchr(buffer,'.')) {
// styler.ColourTo(i-1,SCE_NNCRONTAB_EXTENSION);
// }
else if(modifier.InList(buffer)) {
styler.ColourTo(i-1,SCE_NNCRONTAB_MODIFIER );
} else {
styler.ColourTo(i-1,SCE_NNCRONTAB_DEFAULT);
}
// push back the faulty character
chNext = styler[i--];
}
break;
case SCE_NNCRONTAB_NUMBER:
// stay in CONF_NUMBER state until we find a non-numeric
if( IsASCII(ch) && isdigit(ch) /* || ch == '.' */ ) {
buffer[bufferCount++] = ch;
} else {
state = SCE_NNCRONTAB_DEFAULT;
buffer[bufferCount] = '\0';
// Colourize here... (normal number)
styler.ColourTo(i-1,SCE_NNCRONTAB_NUMBER);
// push back a character
chNext = styler[i--];
}
break;
}
}
delete []buffer;
}
static const char * const cronWordListDesc[] = {
"Section keywords and Forth words",
"nnCrontab keywords",
"Modifiers",
0
};
LexerModule lmNncrontab(SCLEX_NNCRONTAB, ColouriseNncrontabDoc, "nncrontab", 0, cronWordListDesc);

View File

@ -0,0 +1,215 @@
// Scintilla source code edit control
/** @file LexCsound.cxx
** Lexer for Csound (Orchestra & Score)
** Written by Georg Ritter - <ritterfuture A T gmail D O T com>
**/
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// 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;
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 == '.' ||
ch == '%' || ch == '@' || ch == '$' || ch == '?');
}
static inline bool IsCsoundOperator(char ch) {
if (IsASCII(ch) && 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 == ':')
return true;
return false;
}
static void ColouriseCsoundDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
WordList &opcode = *keywordlists[0];
WordList &headerStmt = *keywordlists[1];
WordList &otherKeyword = *keywordlists[2];
// Do not leak onto next line
if (initStyle == SCE_CSOUND_STRINGEOL)
initStyle = SCE_CSOUND_DEFAULT;
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward())
{
// 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_CSOUND_OPERATOR) {
if (!IsCsoundOperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_CSOUND_DEFAULT);
}
}else if (sc.state == SCE_CSOUND_NUMBER) {
if (!IsAWordChar(sc.ch)) {
sc.SetState(SCE_CSOUND_DEFAULT);
}
} else if (sc.state == SCE_CSOUND_IDENTIFIER) {
if (!IsAWordChar(sc.ch) ) {
char s[100];
sc.GetCurrent(s, sizeof(s));
if (opcode.InList(s)) {
sc.ChangeState(SCE_CSOUND_OPCODE);
} else if (headerStmt.InList(s)) {
sc.ChangeState(SCE_CSOUND_HEADERSTMT);
} else if (otherKeyword.InList(s)) {
sc.ChangeState(SCE_CSOUND_USERKEYWORD);
} else if (s[0] == 'p') {
sc.ChangeState(SCE_CSOUND_PARAM);
} else if (s[0] == 'a') {
sc.ChangeState(SCE_CSOUND_ARATE_VAR);
} else if (s[0] == 'k') {
sc.ChangeState(SCE_CSOUND_KRATE_VAR);
} else if (s[0] == 'i') { // covers both i-rate variables and i-statements
sc.ChangeState(SCE_CSOUND_IRATE_VAR);
} else if (s[0] == 'g') {
sc.ChangeState(SCE_CSOUND_GLOBAL_VAR);
}
sc.SetState(SCE_CSOUND_DEFAULT);
}
}
else if (sc.state == SCE_CSOUND_COMMENT ) {
if (sc.atLineEnd) {
sc.SetState(SCE_CSOUND_DEFAULT);
}
}
else if ((sc.state == SCE_CSOUND_ARATE_VAR) ||
(sc.state == SCE_CSOUND_KRATE_VAR) ||
(sc.state == SCE_CSOUND_IRATE_VAR)) {
if (!IsAWordChar(sc.ch)) {
sc.SetState(SCE_CSOUND_DEFAULT);
}
}
// Determine if a new state should be entered.
if (sc.state == SCE_CSOUND_DEFAULT) {
if (sc.ch == ';'){
sc.SetState(SCE_CSOUND_COMMENT);
} else if (isdigit(sc.ch) || (sc.ch == '.' && isdigit(sc.chNext))) {
sc.SetState(SCE_CSOUND_NUMBER);
} else if (IsAWordStart(sc.ch)) {
sc.SetState(SCE_CSOUND_IDENTIFIER);
} else if (IsCsoundOperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_CSOUND_OPERATOR);
} else if (sc.ch == 'p') {
sc.SetState(SCE_CSOUND_PARAM);
} else if (sc.ch == 'a') {
sc.SetState(SCE_CSOUND_ARATE_VAR);
} else if (sc.ch == 'k') {
sc.SetState(SCE_CSOUND_KRATE_VAR);
} else if (sc.ch == 'i') { // covers both i-rate variables and i-statements
sc.SetState(SCE_CSOUND_IRATE_VAR);
} else if (sc.ch == 'g') {
sc.SetState(SCE_CSOUND_GLOBAL_VAR);
}
}
}
sc.Complete();
}
static void FoldCsoundInstruments(Sci_PositionU startPos, Sci_Position length, int /* initStyle */, WordList *[],
Accessor &styler) {
Sci_PositionU lengthDoc = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
int stylePrev = 0;
int styleNext = styler.StyleAt(startPos);
for (Sci_PositionU 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 ((stylePrev != SCE_CSOUND_OPCODE) && (style == SCE_CSOUND_OPCODE)) {
char s[20];
unsigned int j = 0;
while ((j < (sizeof(s) - 1)) && (iswordchar(styler[i + j]))) {
s[j] = styler[i + j];
j++;
}
s[j] = '\0';
if (strcmp(s, "instr") == 0)
levelCurrent++;
if (strcmp(s, "endin") == 0)
levelCurrent--;
}
if (atEOL) {
int lev = levelPrev;
if (visibleChars == 0)
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++;
stylePrev = style;
}
// 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 csoundWordListDesc[] = {
"Opcodes",
"Header Statements",
"User keywords",
0
};
LexerModule lmCsound(SCLEX_CSOUND, ColouriseCsoundDoc, "csound", FoldCsoundInstruments, csoundWordListDesc);

View File

@ -0,0 +1,571 @@
/** @file LexD.cxx
** Lexer for D.
**
** Copyright (c) 2006 by Waldemar Augustyn <waldemar@wdmsys.com>
** Converted to lexer object and added further folding features/properties by "Udo Lechner" <dlchnr(at)gmx(dot)net>
**/
// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
// 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 <map>
#include <functional>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "DefaultLexer.h"
using namespace Scintilla;
using namespace Lexilla;
/* Nested comments require keeping the value of the nesting level for every
position in the document. But since scintilla always styles line by line,
we only need to store one value per line. The non-negative number indicates
nesting level at the end of the line.
*/
// Underscore, letter, digit and universal alphas from C99 Appendix D.
static bool IsWordStart(int ch) {
return (IsASCII(ch) && (isalpha(ch) || ch == '_')) || !IsASCII(ch);
}
static bool IsWord(int ch) {
return (IsASCII(ch) && (isalnum(ch) || ch == '_')) || !IsASCII(ch);
}
static bool IsDoxygen(int ch) {
if (IsASCII(ch) && islower(ch))
return true;
if (ch == '$' || ch == '@' || ch == '\\' ||
ch == '&' || ch == '#' || ch == '<' || ch == '>' ||
ch == '{' || ch == '}' || ch == '[' || ch == ']')
return true;
return false;
}
static bool IsStringSuffix(int ch) {
return ch == 'c' || ch == 'w' || ch == 'd';
}
static bool IsStreamCommentStyle(int style) {
return style == SCE_D_COMMENT ||
style == SCE_D_COMMENTDOC ||
style == SCE_D_COMMENTDOCKEYWORD ||
style == SCE_D_COMMENTDOCKEYWORDERROR;
}
// An individual named option for use in an OptionSet
// Options used for LexerD
struct OptionsD {
bool fold;
bool foldSyntaxBased;
bool foldComment;
bool foldCommentMultiline;
bool foldCommentExplicit;
std::string foldExplicitStart;
std::string foldExplicitEnd;
bool foldExplicitAnywhere;
bool foldCompact;
int foldAtElseInt;
bool foldAtElse;
OptionsD() {
fold = false;
foldSyntaxBased = true;
foldComment = false;
foldCommentMultiline = true;
foldCommentExplicit = true;
foldExplicitStart = "";
foldExplicitEnd = "";
foldExplicitAnywhere = false;
foldCompact = true;
foldAtElseInt = -1;
foldAtElse = false;
}
};
static const char * const dWordLists[] = {
"Primary keywords and identifiers",
"Secondary keywords and identifiers",
"Documentation comment keywords",
"Type definitions and aliases",
"Keywords 5",
"Keywords 6",
"Keywords 7",
0,
};
struct OptionSetD : public OptionSet<OptionsD> {
OptionSetD() {
DefineProperty("fold", &OptionsD::fold);
DefineProperty("fold.d.syntax.based", &OptionsD::foldSyntaxBased,
"Set this property to 0 to disable syntax based folding.");
DefineProperty("fold.comment", &OptionsD::foldComment);
DefineProperty("fold.d.comment.multiline", &OptionsD::foldCommentMultiline,
"Set this property to 0 to disable folding multi-line comments when fold.comment=1.");
DefineProperty("fold.d.comment.explicit", &OptionsD::foldCommentExplicit,
"Set this property to 0 to disable folding explicit fold points when fold.comment=1.");
DefineProperty("fold.d.explicit.start", &OptionsD::foldExplicitStart,
"The string to use for explicit fold start points, replacing the standard //{.");
DefineProperty("fold.d.explicit.end", &OptionsD::foldExplicitEnd,
"The string to use for explicit fold end points, replacing the standard //}.");
DefineProperty("fold.d.explicit.anywhere", &OptionsD::foldExplicitAnywhere,
"Set this property to 1 to enable explicit fold points anywhere, not just in line comments.");
DefineProperty("fold.compact", &OptionsD::foldCompact);
DefineProperty("lexer.d.fold.at.else", &OptionsD::foldAtElseInt,
"This option enables D folding on a \"} else {\" line of an if statement.");
DefineProperty("fold.at.else", &OptionsD::foldAtElse);
DefineWordListSets(dWordLists);
}
};
class LexerD : public DefaultLexer {
bool caseSensitive;
WordList keywords;
WordList keywords2;
WordList keywords3;
WordList keywords4;
WordList keywords5;
WordList keywords6;
WordList keywords7;
OptionsD options;
OptionSetD osD;
public:
LexerD(bool caseSensitive_) :
DefaultLexer("D", SCLEX_D),
caseSensitive(caseSensitive_) {
}
virtual ~LexerD() {
}
void SCI_METHOD Release() override {
delete this;
}
int SCI_METHOD Version() const override {
return lvRelease5;
}
const char * SCI_METHOD PropertyNames() override {
return osD.PropertyNames();
}
int SCI_METHOD PropertyType(const char *name) override {
return osD.PropertyType(name);
}
const char * SCI_METHOD DescribeProperty(const char *name) override {
return osD.DescribeProperty(name);
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
const char * SCI_METHOD PropertyGet(const char *key) override {
return osD.PropertyGet(key);
}
const char * SCI_METHOD DescribeWordListSets() override {
return osD.DescribeWordListSets();
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void * SCI_METHOD PrivateCall(int, void *) override {
return 0;
}
static ILexer5 *LexerFactoryD() {
return new LexerD(true);
}
};
Sci_Position SCI_METHOD LexerD::PropertySet(const char *key, const char *val) {
if (osD.PropertySet(&options, key, val)) {
return 0;
}
return -1;
}
Sci_Position SCI_METHOD LexerD::WordListSet(int n, const char *wl) {
WordList *wordListN = 0;
switch (n) {
case 0:
wordListN = &keywords;
break;
case 1:
wordListN = &keywords2;
break;
case 2:
wordListN = &keywords3;
break;
case 3:
wordListN = &keywords4;
break;
case 4:
wordListN = &keywords5;
break;
case 5:
wordListN = &keywords6;
break;
case 6:
wordListN = &keywords7;
break;
}
Sci_Position firstModification = -1;
if (wordListN) {
WordList wlNew;
wlNew.Set(wl);
if (*wordListN != wlNew) {
wordListN->Set(wl);
firstModification = 0;
}
}
return firstModification;
}
void SCI_METHOD LexerD::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
LexAccessor styler(pAccess);
int styleBeforeDCKeyword = SCE_D_DEFAULT;
StyleContext sc(startPos, length, initStyle, styler);
Sci_Position curLine = styler.GetLine(startPos);
int curNcLevel = curLine > 0? styler.GetLineState(curLine-1): 0;
bool numFloat = false; // Float literals have '+' and '-' signs
bool numHex = false;
for (; sc.More(); sc.Forward()) {
if (sc.atLineStart) {
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, curNcLevel);
}
// Determine if the current state should terminate.
switch (sc.state) {
case SCE_D_OPERATOR:
sc.SetState(SCE_D_DEFAULT);
break;
case SCE_D_NUMBER:
// We accept almost anything because of hex. and number suffixes
if (IsASCII(sc.ch) && (isalnum(sc.ch) || sc.ch == '_')) {
continue;
} else if (sc.ch == '.' && sc.chNext != '.' && !numFloat) {
// Don't parse 0..2 as number.
numFloat=true;
continue;
} else if ( ( sc.ch == '-' || sc.ch == '+' ) && ( /*sign and*/
( !numHex && ( sc.chPrev == 'e' || sc.chPrev == 'E' ) ) || /*decimal or*/
( sc.chPrev == 'p' || sc.chPrev == 'P' ) ) ) { /*hex*/
// Parse exponent sign in float literals: 2e+10 0x2e+10
continue;
} else {
sc.SetState(SCE_D_DEFAULT);
}
break;
case SCE_D_IDENTIFIER:
if (!IsWord(sc.ch)) {
char s[1000];
if (caseSensitive) {
sc.GetCurrent(s, sizeof(s));
} else {
sc.GetCurrentLowered(s, sizeof(s));
}
if (keywords.InList(s)) {
sc.ChangeState(SCE_D_WORD);
} else if (keywords2.InList(s)) {
sc.ChangeState(SCE_D_WORD2);
} else if (keywords4.InList(s)) {
sc.ChangeState(SCE_D_TYPEDEF);
} else if (keywords5.InList(s)) {
sc.ChangeState(SCE_D_WORD5);
} else if (keywords6.InList(s)) {
sc.ChangeState(SCE_D_WORD6);
} else if (keywords7.InList(s)) {
sc.ChangeState(SCE_D_WORD7);
}
sc.SetState(SCE_D_DEFAULT);
}
break;
case SCE_D_COMMENT:
if (sc.Match('*', '/')) {
sc.Forward();
sc.ForwardSetState(SCE_D_DEFAULT);
}
break;
case SCE_D_COMMENTDOC:
if (sc.Match('*', '/')) {
sc.Forward();
sc.ForwardSetState(SCE_D_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))) {
styleBeforeDCKeyword = SCE_D_COMMENTDOC;
sc.SetState(SCE_D_COMMENTDOCKEYWORD);
}
}
break;
case SCE_D_COMMENTLINE:
if (sc.atLineStart) {
sc.SetState(SCE_D_DEFAULT);
}
break;
case SCE_D_COMMENTLINEDOC:
if (sc.atLineStart) {
sc.SetState(SCE_D_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 == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) {
styleBeforeDCKeyword = SCE_D_COMMENTLINEDOC;
sc.SetState(SCE_D_COMMENTDOCKEYWORD);
}
}
break;
case SCE_D_COMMENTDOCKEYWORD:
if ((styleBeforeDCKeyword == SCE_D_COMMENTDOC) && sc.Match('*', '/')) {
sc.ChangeState(SCE_D_COMMENTDOCKEYWORDERROR);
sc.Forward();
sc.ForwardSetState(SCE_D_DEFAULT);
} else if (!IsDoxygen(sc.ch)) {
char s[100];
if (caseSensitive) {
sc.GetCurrent(s, sizeof(s));
} else {
sc.GetCurrentLowered(s, sizeof(s));
}
if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) {
sc.ChangeState(SCE_D_COMMENTDOCKEYWORDERROR);
}
sc.SetState(styleBeforeDCKeyword);
}
break;
case SCE_D_COMMENTNESTED:
if (sc.Match('+', '/')) {
if (curNcLevel > 0)
curNcLevel -= 1;
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, curNcLevel);
sc.Forward();
if (curNcLevel == 0) {
sc.ForwardSetState(SCE_D_DEFAULT);
}
} else if (sc.Match('/','+')) {
curNcLevel += 1;
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, curNcLevel);
sc.Forward();
}
break;
case SCE_D_STRING:
if (sc.ch == '\\') {
if (sc.chNext == '"' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '"') {
if(IsStringSuffix(sc.chNext))
sc.Forward();
sc.ForwardSetState(SCE_D_DEFAULT);
}
break;
case SCE_D_CHARACTER:
if (sc.atLineEnd) {
sc.ChangeState(SCE_D_STRINGEOL);
} else if (sc.ch == '\\') {
if (sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\'') {
// Char has no suffixes
sc.ForwardSetState(SCE_D_DEFAULT);
}
break;
case SCE_D_STRINGEOL:
if (sc.atLineStart) {
sc.SetState(SCE_D_DEFAULT);
}
break;
case SCE_D_STRINGB:
if (sc.ch == '`') {
if(IsStringSuffix(sc.chNext))
sc.Forward();
sc.ForwardSetState(SCE_D_DEFAULT);
}
break;
case SCE_D_STRINGR:
if (sc.ch == '"') {
if(IsStringSuffix(sc.chNext))
sc.Forward();
sc.ForwardSetState(SCE_D_DEFAULT);
}
break;
}
// Determine if a new state should be entered.
if (sc.state == SCE_D_DEFAULT) {
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_D_NUMBER);
numFloat = sc.ch == '.';
// Remember hex literal
numHex = sc.ch == '0' && ( sc.chNext == 'x' || sc.chNext == 'X' );
} else if ( (sc.ch == 'r' || sc.ch == 'x' || sc.ch == 'q')
&& sc.chNext == '"' ) {
// Limited support for hex and delimited strings: parse as r""
sc.SetState(SCE_D_STRINGR);
sc.Forward();
} else if (IsWordStart(sc.ch) || sc.ch == '$') {
sc.SetState(SCE_D_IDENTIFIER);
} else if (sc.Match('/','+')) {
curNcLevel += 1;
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, curNcLevel);
sc.SetState(SCE_D_COMMENTNESTED);
sc.Forward();
} else if (sc.Match('/', '*')) {
if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style
sc.SetState(SCE_D_COMMENTDOC);
} else {
sc.SetState(SCE_D_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_D_COMMENTLINEDOC);
else
sc.SetState(SCE_D_COMMENTLINE);
} else if (sc.ch == '"') {
sc.SetState(SCE_D_STRING);
} else if (sc.ch == '\'') {
sc.SetState(SCE_D_CHARACTER);
} else if (sc.ch == '`') {
sc.SetState(SCE_D_STRINGB);
} else if (isoperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_D_OPERATOR);
if (sc.ch == '.' && sc.chNext == '.') sc.Forward(); // Range operator
}
}
}
sc.Complete();
}
// 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 {".
void SCI_METHOD LexerD::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
if (!options.fold)
return;
LexAccessor styler(pAccess);
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position 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;
bool foldAtElse = options.foldAtElseInt >= 0 ? options.foldAtElseInt != 0 : options.foldAtElse;
const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty();
for (Sci_PositionU 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 (options.foldComment && options.foldCommentMultiline && 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 (options.foldComment && options.foldCommentExplicit && ((style == SCE_D_COMMENTLINE) || options.foldExplicitAnywhere)) {
if (userDefinedFoldMarkers) {
if (styler.Match(i, options.foldExplicitStart.c_str())) {
levelNext++;
} else if (styler.Match(i, options.foldExplicitEnd.c_str())) {
levelNext--;
}
} else {
if ((ch == '/') && (chNext == '/')) {
char chNext2 = styler.SafeGetCharAt(i + 2);
if (chNext2 == '{') {
levelNext++;
} else if (chNext2 == '}') {
levelNext--;
}
}
}
}
if (options.foldSyntaxBased && (style == SCE_D_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 || (i == endPos-1)) {
if (options.foldComment && options.foldCommentMultiline) { // Handle nested comments
int nc;
nc = styler.GetLineState(lineCurrent);
nc -= lineCurrent>0? styler.GetLineState(lineCurrent-1): 0;
levelNext += nc;
}
int levelUse = levelCurrent;
if (options.foldSyntaxBased && foldAtElse) {
levelUse = levelMinCurrent;
}
int lev = levelUse | levelNext << 16;
if (visibleChars == 0 && options.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 (!IsASpace(ch))
visibleChars++;
}
}
LexerModule lmD(SCLEX_D, LexerD::LexerFactoryD, "d", dWordLists);

View File

@ -0,0 +1,234 @@
// Scintilla source code edit control
/** @file LexDMAP.cxx
** Lexer for MSC Nastran DMAP.
** Written by Mark Robinson, based on the Fortran lexer by Chuan-jian Shen, Last changed Aug. 2013
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// 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"
/***************************************/
#if defined(__clang__) && !defined(__APPLE__)
// Disable warning for numNonBlank
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#endif
using namespace Lexilla;
/***********************************************/
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '%');
}
/**********************************************/
static inline bool IsAWordStart(const int ch) {
return (ch < 0x80) && (isalnum(ch));
}
/***************************************/
static void ColouriseDMAPDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler) {
WordList &keywords = *keywordlists[0];
WordList &keywords2 = *keywordlists[1];
WordList &keywords3 = *keywordlists[2];
/***************************************/
Sci_Position posLineStart = 0, numNonBlank = 0;
Sci_Position endPos = startPos + length;
/***************************************/
// backtrack to the nearest keyword
while ((startPos > 1) && (styler.StyleAt(startPos) != SCE_DMAP_WORD)) {
startPos--;
}
startPos = styler.LineStart(styler.GetLine(startPos));
initStyle = styler.StyleAt(startPos - 1);
StyleContext sc(startPos, endPos-startPos, initStyle, styler);
/***************************************/
for (; sc.More(); sc.Forward()) {
// remember the start position of the line
if (sc.atLineStart) {
posLineStart = sc.currentPos;
numNonBlank = 0;
sc.SetState(SCE_DMAP_DEFAULT);
}
if (!IsASpaceOrTab(sc.ch)) numNonBlank ++;
/***********************************************/
// Handle data appearing after column 72; it is ignored
Sci_Position toLineStart = sc.currentPos - posLineStart;
if (toLineStart >= 72 || sc.ch == '$') {
sc.SetState(SCE_DMAP_COMMENT);
while (!sc.atLineEnd && sc.More()) sc.Forward(); // Until line end
continue;
}
/***************************************/
// Determine if the current state should terminate.
if (sc.state == SCE_DMAP_OPERATOR) {
sc.SetState(SCE_DMAP_DEFAULT);
} else if (sc.state == SCE_DMAP_NUMBER) {
if (!(IsAWordChar(sc.ch) || sc.ch=='\'' || sc.ch=='\"' || sc.ch=='.')) {
sc.SetState(SCE_DMAP_DEFAULT);
}
} else if (sc.state == SCE_DMAP_IDENTIFIER) {
if (!IsAWordChar(sc.ch) || (sc.ch == '%')) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
if (keywords.InList(s)) {
sc.ChangeState(SCE_DMAP_WORD);
} else if (keywords2.InList(s)) {
sc.ChangeState(SCE_DMAP_WORD2);
} else if (keywords3.InList(s)) {
sc.ChangeState(SCE_DMAP_WORD3);
}
sc.SetState(SCE_DMAP_DEFAULT);
}
} else if (sc.state == SCE_DMAP_COMMENT) {
if (sc.ch == '\r' || sc.ch == '\n') {
sc.SetState(SCE_DMAP_DEFAULT);
}
} else if (sc.state == SCE_DMAP_STRING1) {
if (sc.ch == '\'') {
if (sc.chNext == '\'') {
sc.Forward();
} else {
sc.ForwardSetState(SCE_DMAP_DEFAULT);
}
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_DMAP_STRINGEOL);
sc.ForwardSetState(SCE_DMAP_DEFAULT);
}
} else if (sc.state == SCE_DMAP_STRING2) {
if (sc.atLineEnd) {
sc.ChangeState(SCE_DMAP_STRINGEOL);
sc.ForwardSetState(SCE_DMAP_DEFAULT);
} else if (sc.ch == '\"') {
if (sc.chNext == '\"') {
sc.Forward();
} else {
sc.ForwardSetState(SCE_DMAP_DEFAULT);
}
}
}
/***************************************/
// Determine if a new state should be entered.
if (sc.state == SCE_DMAP_DEFAULT) {
if (sc.ch == '$') {
sc.SetState(SCE_DMAP_COMMENT);
} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext)) || (sc.ch == '-' && IsADigit(sc.chNext))) {
sc.SetState(SCE_F_NUMBER);
} else if (IsAWordStart(sc.ch)) {
sc.SetState(SCE_DMAP_IDENTIFIER);
} else if (sc.ch == '\"') {
sc.SetState(SCE_DMAP_STRING2);
} else if (sc.ch == '\'') {
sc.SetState(SCE_DMAP_STRING1);
} else if (isoperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_DMAP_OPERATOR);
}
}
}
sc.Complete();
}
/***************************************/
// To determine the folding level depending on keywords
static int classifyFoldPointDMAP(const char* s, const char* prevWord) {
int lev = 0;
if ((strcmp(prevWord, "else") == 0 && strcmp(s, "if") == 0) || strcmp(s, "enddo") == 0 || strcmp(s, "endif") == 0) {
lev = -1;
} else if ((strcmp(prevWord, "do") == 0 && strcmp(s, "while") == 0) || strcmp(s, "then") == 0) {
lev = 1;
}
return lev;
}
// Folding the code
static void FoldDMAPDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *[], Accessor &styler) {
//
// bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
// Do not know how to fold the comment at the moment.
//
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
int style = initStyle;
/***************************************/
Sci_Position lastStart = 0;
char prevWord[32] = "";
/***************************************/
for (Sci_PositionU 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 ((stylePrev == SCE_DMAP_DEFAULT || stylePrev == SCE_DMAP_OPERATOR || stylePrev == SCE_DMAP_COMMENT) && (style == SCE_DMAP_WORD)) {
// Store last word and label start point.
lastStart = i;
}
/***************************************/
if (style == SCE_DMAP_WORD) {
if(iswordchar(ch) && !iswordchar(chNext)) {
char s[32];
Sci_PositionU k;
for(k=0; (k<31 ) && (k<i-lastStart+1 ); k++) {
s[k] = static_cast<char>(tolower(styler[lastStart+k]));
}
s[k] = '\0';
levelCurrent += classifyFoldPointDMAP(s, prevWord);
strcpy(prevWord, s);
}
}
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;
strcpy(prevWord, "");
}
/***************************************/
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 DMAPWordLists[] = {
"Primary keywords and identifiers",
"Intrinsic functions",
"Extended and user defined functions",
0,
};
/***************************************/
LexerModule lmDMAP(SCLEX_DMAP, ColouriseDMAPDoc, "DMAP", FoldDMAPDoc, DMAPWordLists);

View File

@ -0,0 +1,367 @@
// Scintilla source code edit control
/** @file LexDMIS.cxx
** Lexer for DMIS.
**/
// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
// Copyright 2013-2014 by Andreas Tscharner <andy@vis.ethz.ch>
// The License.txt file describes the conditions under which this software may be distributed.
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cctype>
#include <string>
#include <string_view>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "DefaultLexer.h"
using namespace Lexilla;
static const char *const DMISWordListDesc[] = {
"DMIS Major Words",
"DMIS Minor Words",
"Unsupported DMIS Major Words",
"Unsupported DMIS Minor Words",
"Keywords for code folding start",
"Corresponding keywords for code folding end",
0
};
class LexerDMIS : public DefaultLexer
{
private:
char *m_wordListSets;
WordList m_majorWords;
WordList m_minorWords;
WordList m_unsupportedMajor;
WordList m_unsupportedMinor;
WordList m_codeFoldingStart;
WordList m_codeFoldingEnd;
char * SCI_METHOD UpperCase(char *item);
void SCI_METHOD InitWordListSets(void);
public:
LexerDMIS(void);
virtual ~LexerDMIS(void);
int SCI_METHOD Version() const override {
return Scintilla::lvRelease5;
}
void SCI_METHOD Release() override {
delete this;
}
const char * SCI_METHOD PropertyNames() override {
return NULL;
}
int SCI_METHOD PropertyType(const char *) override {
return -1;
}
const char * SCI_METHOD DescribeProperty(const char *) override {
return NULL;
}
Sci_Position SCI_METHOD PropertySet(const char *, const char *) override {
return -1;
}
const char * SCI_METHOD PropertyGet(const char *) override {
return NULL;
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void * SCI_METHOD PrivateCall(int, void *) override {
return NULL;
}
static ILexer5 *LexerFactoryDMIS() {
return new LexerDMIS;
}
const char * SCI_METHOD DescribeWordListSets() override;
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, Scintilla::IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, Scintilla::IDocument *pAccess) override;
};
char * SCI_METHOD LexerDMIS::UpperCase(char *item)
{
char *itemStart;
itemStart = item;
while (item && *item) {
*item = toupper(*item);
item++;
};
return itemStart;
}
void SCI_METHOD LexerDMIS::InitWordListSets(void)
{
size_t totalLen = 0;
for (int i=0; DMISWordListDesc[i]; i++) {
totalLen += strlen(DMISWordListDesc[i]);
totalLen++;
};
totalLen++;
this->m_wordListSets = new char[totalLen];
memset(this->m_wordListSets, 0, totalLen);
for (int i=0; DMISWordListDesc[i]; i++) {
strcat(this->m_wordListSets, DMISWordListDesc[i]);
strcat(this->m_wordListSets, "\n");
};
}
LexerDMIS::LexerDMIS(void) : DefaultLexer("DMIS", SCLEX_DMIS) {
this->InitWordListSets();
this->m_majorWords.Clear();
this->m_minorWords.Clear();
this->m_unsupportedMajor.Clear();
this->m_unsupportedMinor.Clear();
this->m_codeFoldingStart.Clear();
this->m_codeFoldingEnd.Clear();
}
LexerDMIS::~LexerDMIS(void) {
delete[] this->m_wordListSets;
}
Sci_Position SCI_METHOD LexerDMIS::WordListSet(int n, const char *wl)
{
switch (n) {
case 0:
this->m_majorWords.Clear();
this->m_majorWords.Set(wl);
break;
case 1:
this->m_minorWords.Clear();
this->m_minorWords.Set(wl);
break;
case 2:
this->m_unsupportedMajor.Clear();
this->m_unsupportedMajor.Set(wl);
break;
case 3:
this->m_unsupportedMinor.Clear();
this->m_unsupportedMinor.Set(wl);
break;
case 4:
this->m_codeFoldingStart.Clear();
this->m_codeFoldingStart.Set(wl);
break;
case 5:
this->m_codeFoldingEnd.Clear();
this->m_codeFoldingEnd.Set(wl);
break;
default:
return -1;
break;
}
return 0;
}
const char * SCI_METHOD LexerDMIS::DescribeWordListSets()
{
return this->m_wordListSets;
}
void SCI_METHOD LexerDMIS::Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, Scintilla::IDocument *pAccess)
{
const Sci_PositionU MAX_STR_LEN = 100;
LexAccessor styler(pAccess);
StyleContext scCTX(startPos, lengthDoc, initStyle, styler);
CharacterSet setDMISNumber(CharacterSet::setDigits, ".-+eE");
CharacterSet setDMISWordStart(CharacterSet::setAlpha, "-234", 0x80, true);
CharacterSet setDMISWord(CharacterSet::setAlpha);
bool isIFLine = false;
for (; scCTX.More(); scCTX.Forward()) {
if (scCTX.atLineEnd) {
isIFLine = false;
};
switch (scCTX.state) {
case SCE_DMIS_DEFAULT:
if (scCTX.Match('$', '$')) {
scCTX.SetState(SCE_DMIS_COMMENT);
scCTX.Forward();
};
if (scCTX.Match('\'')) {
scCTX.SetState(SCE_DMIS_STRING);
};
if (IsADigit(scCTX.ch) || ((scCTX.Match('-') || scCTX.Match('+')) && IsADigit(scCTX.chNext))) {
scCTX.SetState(SCE_DMIS_NUMBER);
break;
};
if (setDMISWordStart.Contains(scCTX.ch)) {
scCTX.SetState(SCE_DMIS_KEYWORD);
};
if (scCTX.Match('(') && (!isIFLine)) {
scCTX.SetState(SCE_DMIS_LABEL);
};
break;
case SCE_DMIS_COMMENT:
if (scCTX.atLineEnd) {
scCTX.SetState(SCE_DMIS_DEFAULT);
};
break;
case SCE_DMIS_STRING:
if (scCTX.Match('\'')) {
scCTX.SetState(SCE_DMIS_DEFAULT);
};
break;
case SCE_DMIS_NUMBER:
if (!setDMISNumber.Contains(scCTX.ch)) {
scCTX.SetState(SCE_DMIS_DEFAULT);
};
break;
case SCE_DMIS_KEYWORD:
if (!setDMISWord.Contains(scCTX.ch)) {
char tmpStr[MAX_STR_LEN];
memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
scCTX.GetCurrent(tmpStr, (MAX_STR_LEN-1));
// The following strncpy is copying from a string back onto itself which is weird and causes warnings
// but is harmless so turn off the warning
#if defined(__GNUC__) && !defined(__clang__)
// Disable warning for strncpy
#pragma GCC diagnostic ignored "-Wrestrict"
#endif
strncpy(tmpStr, this->UpperCase(tmpStr), (MAX_STR_LEN-1));
if (this->m_minorWords.InList(tmpStr)) {
scCTX.ChangeState(SCE_DMIS_MINORWORD);
};
if (this->m_majorWords.InList(tmpStr)) {
isIFLine = (strcmp(tmpStr, "IF") == 0);
scCTX.ChangeState(SCE_DMIS_MAJORWORD);
};
if (this->m_unsupportedMajor.InList(tmpStr)) {
scCTX.ChangeState(SCE_DMIS_UNSUPPORTED_MAJOR);
};
if (this->m_unsupportedMinor.InList(tmpStr)) {
scCTX.ChangeState(SCE_DMIS_UNSUPPORTED_MINOR);
};
if (scCTX.Match('(') && (!isIFLine)) {
scCTX.SetState(SCE_DMIS_LABEL);
} else {
scCTX.SetState(SCE_DMIS_DEFAULT);
};
};
break;
case SCE_DMIS_LABEL:
if (scCTX.Match(')')) {
scCTX.SetState(SCE_DMIS_DEFAULT);
};
break;
};
};
scCTX.Complete();
}
void SCI_METHOD LexerDMIS::Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int, Scintilla::IDocument *pAccess)
{
const int MAX_STR_LEN = 100;
LexAccessor styler(pAccess);
Sci_PositionU endPos = startPos + lengthDoc;
char chNext = styler[startPos];
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
int strPos = 0;
bool foldWordPossible = false;
CharacterSet setDMISFoldWord(CharacterSet::setAlpha);
char *tmpStr;
tmpStr = new char[MAX_STR_LEN];
memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
for (Sci_PositionU i=startPos; i<endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i+1);
bool atEOL = ((ch == '\r' && chNext != '\n') || (ch == '\n'));
if (strPos >= (MAX_STR_LEN-1)) {
strPos = MAX_STR_LEN-1;
};
int style = styler.StyleAt(i);
bool noFoldPos = ((style == SCE_DMIS_COMMENT) || (style == SCE_DMIS_STRING));
if (foldWordPossible) {
if (setDMISFoldWord.Contains(ch)) {
tmpStr[strPos++] = ch;
} else {
tmpStr = this->UpperCase(tmpStr);
if (this->m_codeFoldingStart.InList(tmpStr) && (!noFoldPos)) {
levelCurrent++;
};
if (this->m_codeFoldingEnd.InList(tmpStr) && (!noFoldPos)) {
levelCurrent--;
};
memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
strPos = 0;
foldWordPossible = false;
};
} else {
if (setDMISFoldWord.Contains(ch)) {
tmpStr[strPos++] = ch;
foldWordPossible = true;
};
};
if (atEOL || (i == (endPos-1))) {
int lev = levelPrev;
if (levelCurrent > levelPrev) {
lev |= SC_FOLDLEVELHEADERFLAG;
};
if (lev != styler.LevelAt(lineCurrent)) {
styler.SetLevel(lineCurrent, lev);
};
lineCurrent++;
levelPrev = levelCurrent;
};
};
delete[] tmpStr;
}
LexerModule lmDMIS(SCLEX_DMIS, LexerDMIS::LexerFactoryDMIS, "DMIS", DMISWordListDesc);

View File

@ -0,0 +1,611 @@
// Scintilla source code edit control
/** @file LexDataflex.cxx
** Lexer for DataFlex.
** Based on LexPascal.cxx
** Written by Wil van Antwerpen, June 2019
**/
/*
// The License.txt file describes the conditions under which this software may be distributed.
A few words about features of LexDataflex...
Generally speaking LexDataflex tries to support all available DataFlex features (up
to DataFlex 19.1 at this time).
~ FOLDING:
Folding is supported in the following cases:
- Folding of stream-like comments
- Folding of groups of consecutive line comments
- Folding of preprocessor blocks (the following preprocessor blocks are
supported: #IFDEF, #IFNDEF, #ENDIF and #HEADER / #ENDHEADER
blocks),
- Folding of code blocks on appropriate keywords (the following code blocks are
supported: "begin, struct, type, case / end" blocks, class & object
declarations and interface declarations)
Remarks:
- We pass 4 arrays to the lexer:
1. The DataFlex keyword list, these are normal DataFlex keywords
2. The Scope Open list, for example, begin / procedure / while
3. The Scope Close list, for example, end / end_procedure / loop
4. Operator list, for ex. + / - / * / Lt / iand
These lists are all mutually exclusive, scope open words should not be in the keyword list and vice versa
- Folding of code blocks tries to handle all special cases in which folding
should not occur.
~ KEYWORDS:
The list of keywords that can be used in dataflex.properties file (up to DataFlex
19.1):
- Keywords: .. snipped .. see dataflex.properties file.
*/
#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;
static void GetRangeLowered(Sci_PositionU start,
Sci_PositionU end,
Accessor &styler,
char *s,
Sci_PositionU len) {
Sci_PositionU i = 0;
while ((i < end - start + 1) && (i < len-1)) {
s[i] = static_cast<char>(tolower(styler[start + i]));
i++;
}
s[i] = '\0';
}
static void GetForwardRangeLowered(Sci_PositionU start,
CharacterSet &charSet,
Accessor &styler,
char *s,
Sci_PositionU len) {
Sci_PositionU i = 0;
while ((i < len-1) && charSet.Contains(styler.SafeGetCharAt(start + i))) {
s[i] = static_cast<char>(tolower(styler.SafeGetCharAt(start + i)));
i++;
}
s[i] = '\0';
}
enum {
stateInICode = 0x1000,
stateSingleQuoteOpen = 0x2000,
stateDoubleQuoteOpen = 0x4000,
stateFoldInPreprocessor = 0x0100,
stateFoldInCaseStatement = 0x0200,
stateFoldInPreprocessorLevelMask = 0x00FF,
stateFoldMaskAll = 0x0FFF
};
static bool IsFirstDataFlexWord(Sci_Position pos, Accessor &styler) {
Sci_Position line = styler.GetLine(pos);
Sci_Position start_pos = styler.LineStart(line);
for (Sci_Position i = start_pos; i < pos; i++) {
char ch = styler.SafeGetCharAt(i);
if (!(ch == ' ' || ch == '\t'))
return false;
}
return true;
}
inline bool IsADataFlexField(int ch) {
return (ch == '.');
}
static void ClassifyDataFlexWord(WordList *keywordlists[], StyleContext &sc, Accessor &styler) {
WordList& keywords = *keywordlists[0];
WordList& scopeOpen = *keywordlists[1];
WordList& scopeClosed = *keywordlists[2];
WordList& operators = *keywordlists[3];
char s[100];
int oldState;
int newState;
size_t tokenlen;
oldState = sc.state;
newState = oldState;
sc.GetCurrentLowered(s, sizeof(s));
tokenlen = strnlen(s,sizeof(s));
if (keywords.InList(s)) {
// keywords in DataFlex can be used as table column names (file.field) and as such they
// should not be characterized as a keyword. So test for that.
// for ex. somebody using date as field name.
if (!IsADataFlexField(sc.GetRelative(-static_cast<int>(tokenlen+1)))) {
newState = SCE_DF_WORD;
}
}
if (oldState == newState) {
if ((scopeOpen.InList(s) || scopeClosed.InList(s)) && (strcmp(s, "for") != 0) && (strcmp(s, "repeat") != 0)) {
// scope words in DataFlex can be used as table column names (file.field) and as such they
// should not be characterized as a scope word. So test for that.
// for ex. somebody using procedure for field name.
if (!IsADataFlexField(sc.GetRelative(-static_cast<int>(tokenlen+1)))) {
newState = SCE_DF_SCOPEWORD;
}
}
// no code folding on the next words, but just want to paint them like keywords (as they are) (??? doesn't the code to the opposite?)
if (strcmp(s, "if") == 0 ||
strcmp(s, "ifnot") == 0 ||
strcmp(s, "case") == 0 ||
strcmp(s, "else") == 0 ) {
newState = SCE_DF_SCOPEWORD;
}
}
if (oldState != newState && newState == SCE_DF_WORD) {
// a for loop must have for at the start of the line, for is also used in "define abc for 123"
if ( (strcmp(s, "for") == 0) && (IsFirstDataFlexWord(sc.currentPos-3, styler)) ) {
newState = SCE_DF_SCOPEWORD;
}
}
if (oldState != newState && newState == SCE_DF_WORD) {
// a repeat loop must have repeat at the start of the line, repeat is also used in 'move (repeat("d",5)) to sFoo'
if ( (strcmp(s, "repeat") == 0) && (IsFirstDataFlexWord(sc.currentPos-6, styler)) ) {
newState = SCE_DF_SCOPEWORD;
}
}
if (oldState == newState) {
if (operators.InList(s)) {
newState = SCE_DF_OPERATOR;
}
}
if (oldState != newState) {
sc.ChangeState(newState);
}
sc.SetState(SCE_DF_DEFAULT);
}
static void ColouriseDataFlexDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
// bool bSmartHighlighting = styler.GetPropertyInt("lexer.dataflex.smart.highlighting", 1) != 0;
CharacterSet setWordStart(CharacterSet::setAlpha, "_$#@", 0x80, true);
CharacterSet setWord(CharacterSet::setAlphaNum, "_$#@", 0x80, true);
CharacterSet setNumber(CharacterSet::setDigits, ".-+eE");
CharacterSet setHexNumber(CharacterSet::setDigits, "abcdefABCDEF");
CharacterSet setOperator(CharacterSet::setNone, "*+-/<=>^");
Sci_Position curLine = styler.GetLine(startPos);
int curLineState = curLine > 0 ? styler.GetLineState(curLine - 1) : 0;
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
if (sc.atLineEnd) {
// Update the line state, so it can be seen by next line
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, curLineState);
}
// Determine if the current state should terminate.
switch (sc.state) {
case SCE_DF_NUMBER:
if (!setNumber.Contains(sc.ch) || (sc.ch == '.' && sc.chNext == '.')) {
sc.SetState(SCE_DF_DEFAULT);
} else if (sc.ch == '-' || sc.ch == '+') {
if (sc.chPrev != 'E' && sc.chPrev != 'e') {
sc.SetState(SCE_DF_DEFAULT);
}
}
break;
case SCE_DF_IDENTIFIER:
if (!setWord.Contains(sc.ch)) {
ClassifyDataFlexWord(keywordlists, sc, styler);
}
break;
case SCE_DF_HEXNUMBER:
if (!(setHexNumber.Contains(sc.ch) || sc.ch == 'I') ) { // in |CI$22a we also want to color the "I"
sc.SetState(SCE_DF_DEFAULT);
}
break;
case SCE_DF_METATAG:
if (sc.atLineStart || sc.chPrev == '}') {
sc.SetState(SCE_DF_DEFAULT);
}
break;
case SCE_DF_PREPROCESSOR:
if (sc.atLineStart || IsASpaceOrTab(sc.ch)) {
sc.SetState(SCE_DF_DEFAULT);
}
break;
case SCE_DF_IMAGE:
if (sc.atLineStart && sc.Match("/*")) {
sc.Forward(); // these characters are still part of the DF Image
sc.ForwardSetState(SCE_DF_DEFAULT);
}
break;
case SCE_DF_PREPROCESSOR2:
// we don't have inline comments or preprocessor2 commands
//if (sc.Match('*', ')')) {
// sc.Forward();
// sc.ForwardSetState(SCE_DF_DEFAULT);
//}
break;
case SCE_DF_COMMENTLINE:
if (sc.atLineStart) {
sc.SetState(SCE_DF_DEFAULT);
}
break;
case SCE_DF_STRING:
if (sc.atLineEnd) {
sc.ChangeState(SCE_DF_STRINGEOL);
} else if (sc.ch == '\'' && sc.chNext == '\'') {
sc.Forward();
} else if (sc.ch == '\"' && sc.chNext == '\"') {
sc.Forward();
} else if (sc.ch == '\'' || sc.ch == '\"') {
if (sc.ch == '\'' && (curLineState & stateSingleQuoteOpen) ) {
curLineState &= ~(stateSingleQuoteOpen);
sc.ForwardSetState(SCE_DF_DEFAULT);
}
else if (sc.ch == '\"' && (curLineState & stateDoubleQuoteOpen) ) {
curLineState &= ~(stateDoubleQuoteOpen);
sc.ForwardSetState(SCE_DF_DEFAULT);
}
}
break;
case SCE_DF_STRINGEOL:
if (sc.atLineStart) {
sc.SetState(SCE_DF_DEFAULT);
}
break;
case SCE_DF_SCOPEWORD:
//if (!setHexNumber.Contains(sc.ch) && sc.ch != '$') {
// sc.SetState(SCE_DF_DEFAULT);
//}
break;
case SCE_DF_OPERATOR:
// if (bSmartHighlighting && sc.chPrev == ';') {
// curLineState &= ~(stateInProperty | stateInExport);
// }
sc.SetState(SCE_DF_DEFAULT);
break;
case SCE_DF_ICODE:
if (sc.atLineStart || IsASpace(sc.ch) || isoperator(sc.ch)) {
sc.SetState(SCE_DF_DEFAULT);
}
break;
}
// Determine if a new state should be entered.
if (sc.state == SCE_DF_DEFAULT) {
if (IsADigit(sc.ch)) {
sc.SetState(SCE_DF_NUMBER);
} else if (sc.Match('/', '/') || sc.Match("#REM")) {
sc.SetState(SCE_DF_COMMENTLINE);
} else if ((sc.ch == '#' && !sc.Match("#REM")) && IsFirstDataFlexWord(sc.currentPos, styler)) {
sc.SetState(SCE_DF_PREPROCESSOR);
// || (sc.ch == '|' && sc.chNext == 'C' && sc.GetRelativeCharacter(2) == 'I' && sc.GetRelativeCharacter(3) == '$') ) {
} else if ((sc.ch == '$' && ((!setWord.Contains(sc.chPrev)) || sc.chPrev == 'I' ) ) || (sc.Match("|CI$")) ) {
sc.SetState(SCE_DF_HEXNUMBER); // start with $ and previous character not in a..zA..Z0..9 excluding "I" OR start with |CI$
} else if (setWordStart.Contains(sc.ch)) {
sc.SetState(SCE_DF_IDENTIFIER);
} else if (sc.ch == '{') {
sc.SetState(SCE_DF_METATAG);
//} else if (sc.Match("(*$")) {
// sc.SetState(SCE_DF_PREPROCESSOR2);
} else if (sc.ch == '/' && setWord.Contains(sc.chNext) && sc.atLineStart) {
sc.SetState(SCE_DF_IMAGE);
// sc.Forward(); // Eat the * so it isn't used for the end of the comment
} else if (sc.ch == '\'' || sc.ch == '\"') {
if (sc.ch == '\'' && !(curLineState & stateDoubleQuoteOpen)) {
curLineState |= stateSingleQuoteOpen;
} else if (sc.ch == '\"' && !(curLineState & stateSingleQuoteOpen)) {
curLineState |= stateDoubleQuoteOpen;
}
sc.SetState(SCE_DF_STRING);
} else if (setOperator.Contains(sc.ch)) {
sc.SetState(SCE_DF_OPERATOR);
// } else if (curLineState & stateInICode) {
// ICode start ! in a string followed by close string mark is not icode
} else if ((sc.ch == '!') && !(sc.ch == '!' && ((sc.chNext == '\"') || (sc.ch == '\'')) )) {
sc.SetState(SCE_DF_ICODE);
}
}
}
if (sc.state == SCE_DF_IDENTIFIER && setWord.Contains(sc.chPrev)) {
ClassifyDataFlexWord(keywordlists, sc, styler);
}
sc.Complete();
}
static bool IsStreamCommentStyle(int style) {
return style == SCE_DF_IMAGE;
}
static bool IsCommentLine(Sci_Position line, Accessor &styler) {
Sci_Position pos = styler.LineStart(line);
Sci_Position eolPos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eolPos; i++) {
char ch = styler[i];
char chNext = styler.SafeGetCharAt(i + 1);
int style = styler.StyleAt(i);
if (ch == '/' && chNext == '/' && style == SCE_DF_COMMENTLINE) {
return true;
} else if (!IsASpaceOrTab(ch)) {
return false;
}
}
return false;
}
static unsigned int GetFoldInPreprocessorLevelFlag(int lineFoldStateCurrent) {
return lineFoldStateCurrent & stateFoldInPreprocessorLevelMask;
}
static void SetFoldInPreprocessorLevelFlag(int &lineFoldStateCurrent, unsigned int nestLevel) {
lineFoldStateCurrent &= ~stateFoldInPreprocessorLevelMask;
lineFoldStateCurrent |= nestLevel & stateFoldInPreprocessorLevelMask;
}
static int ClassifyDataFlexPreprocessorFoldPoint(int &levelCurrent, int &lineFoldStateCurrent,
Sci_PositionU startPos, Accessor &styler) {
CharacterSet setWord(CharacterSet::setAlpha);
char s[100]; // Size of the longest possible keyword + one additional character + null
GetForwardRangeLowered(startPos, setWord, styler, s, sizeof(s));
size_t iLen = strnlen(s,sizeof(s));
size_t iWordSize = 0;
unsigned int nestLevel = GetFoldInPreprocessorLevelFlag(lineFoldStateCurrent);
if (strcmp(s, "command") == 0 ||
// The #if/#ifdef etcetera commands are not currently foldable as it is easy to write code that
// breaks the collaps logic, so we keep things simple and not include that for now.
strcmp(s, "header") == 0) {
nestLevel++;
SetFoldInPreprocessorLevelFlag(lineFoldStateCurrent, nestLevel);
lineFoldStateCurrent |= stateFoldInPreprocessor;
levelCurrent++;
iWordSize = iLen;
} else if (strcmp(s, "endcommand") == 0 ||
strcmp(s, "endheader") == 0) {
nestLevel--;
SetFoldInPreprocessorLevelFlag(lineFoldStateCurrent, nestLevel);
if (nestLevel == 0) {
lineFoldStateCurrent &= ~stateFoldInPreprocessor;
}
levelCurrent--;
iWordSize = iLen;
if (levelCurrent < SC_FOLDLEVELBASE) {
levelCurrent = SC_FOLDLEVELBASE;
}
}
return static_cast<int>(iWordSize);
}
static void ClassifyDataFlexWordFoldPoint(int &levelCurrent, int &lineFoldStateCurrent,
Sci_PositionU lastStart, Sci_PositionU currentPos, WordList *[], Accessor &styler) {
char s[100];
// property fold.dataflex.compilerlist
// Set to 1 for enabling the code folding feature in *.prn files
bool foldPRN = styler.GetPropertyInt("fold.dataflex.compilerlist",0) != 0;
GetRangeLowered(lastStart, currentPos, styler, s, sizeof(s));
if (strcmp(s, "case") == 0) {
lineFoldStateCurrent |= stateFoldInCaseStatement;
} else if (strcmp(s, "begin") == 0) {
levelCurrent++;
} else if (strcmp(s, "for") == 0 ||
strcmp(s, "while") == 0 ||
strcmp(s, "repeat") == 0 ||
strcmp(s, "for_all") == 0 ||
strcmp(s, "struct") == 0 ||
strcmp(s, "type") == 0 ||
strcmp(s, "begin_row") == 0 ||
strcmp(s, "item_list") == 0 ||
strcmp(s, "begin_constraints") == 0 ||
strcmp(s, "begin_transaction") == 0 ||
strcmp(s, "enum_list") == 0 ||
strcmp(s, "class") == 0 ||
strcmp(s, "object") == 0 ||
strcmp(s, "cd_popup_object") == 0 ||
strcmp(s, "procedure") == 0 ||
strcmp(s, "procedure_section") == 0 ||
strcmp(s, "function") == 0 ) {
if ((IsFirstDataFlexWord(lastStart, styler )) || foldPRN) {
levelCurrent++;
}
} else if (strcmp(s, "end") == 0) { // end is not always the first keyword, for example "case end"
levelCurrent--;
if (levelCurrent < SC_FOLDLEVELBASE) {
levelCurrent = SC_FOLDLEVELBASE;
}
} else if (strcmp(s, "loop") == 0 ||
strcmp(s, "until") == 0 ||
strcmp(s, "end_class") == 0 ||
strcmp(s, "end_object") == 0 ||
strcmp(s, "cd_end_object") == 0 ||
strcmp(s, "end_procedure") == 0 ||
strcmp(s, "end_function") == 0 ||
strcmp(s, "end_for_all") == 0 ||
strcmp(s, "end_struct") == 0 ||
strcmp(s, "end_type") == 0 ||
strcmp(s, "end_row") == 0 ||
strcmp(s, "end_item_list") == 0 ||
strcmp(s, "end_constraints") == 0 ||
strcmp(s, "end_transaction") == 0 ||
strcmp(s, "end_enum_list") == 0 ) {
// lineFoldStateCurrent &= ~stateFoldInRecord;
if ((IsFirstDataFlexWord(lastStart, styler )) || foldPRN) {
levelCurrent--;
if (levelCurrent < SC_FOLDLEVELBASE) {
levelCurrent = SC_FOLDLEVELBASE;
}
}
}
}
static void ClassifyDataFlexMetaDataFoldPoint(int &levelCurrent,
Sci_PositionU lastStart, Sci_PositionU currentPos, WordList *[], Accessor &styler) {
char s[100];
GetRangeLowered(lastStart, currentPos, styler, s, sizeof(s));
if (strcmp(s, "#beginsection") == 0) {
levelCurrent++;
} else if (strcmp(s, "#endsection") == 0) {
levelCurrent--;
if (levelCurrent < SC_FOLDLEVELBASE) {
levelCurrent = SC_FOLDLEVELBASE;
}
}
}
static void FoldDataFlexDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
int lineFoldStateCurrent = lineCurrent > 0 ? styler.GetLineState(lineCurrent - 1) & stateFoldMaskAll : 0;
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
int style = initStyle;
int iWordSize;
Sci_Position lastStart = 0;
CharacterSet setWord(CharacterSet::setAlphaNum, "_$#@", 0x80, true);
for (Sci_PositionU 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)) {
levelCurrent++;
} else if (!IsStreamCommentStyle(styleNext)) {
levelCurrent--;
}
}
if (foldComment && atEOL && IsCommentLine(lineCurrent, styler))
{
if (!IsCommentLine(lineCurrent - 1, styler)
&& IsCommentLine(lineCurrent + 1, styler))
levelCurrent++;
else if (IsCommentLine(lineCurrent - 1, styler)
&& !IsCommentLine(lineCurrent+1, styler))
levelCurrent--;
}
if (foldPreprocessor) {
if (style == SCE_DF_PREPROCESSOR) {
iWordSize = ClassifyDataFlexPreprocessorFoldPoint(levelCurrent, lineFoldStateCurrent, i + 1, styler);
//} else if (style == SCE_DF_PREPROCESSOR2 && ch == '(' && chNext == '*'
// && styler.SafeGetCharAt(i + 2) == '$') {
// ClassifyDataFlexPreprocessorFoldPoint(levelCurrent, lineFoldStateCurrent, i + 3, styler);
i = i + iWordSize;
}
}
if (stylePrev != SCE_DF_SCOPEWORD && style == SCE_DF_SCOPEWORD)
{
// Store last word start point.
lastStart = i;
}
if (stylePrev == SCE_DF_SCOPEWORD) {
if(setWord.Contains(ch) && !setWord.Contains(chNext)) {
ClassifyDataFlexWordFoldPoint(levelCurrent, lineFoldStateCurrent, lastStart, i, keywordlists, styler);
}
}
if (stylePrev == SCE_DF_METATAG && ch == '#')
{
// Store last word start point.
lastStart = i;
}
if (stylePrev == SCE_DF_METATAG) {
if(setWord.Contains(ch) && !setWord.Contains(chNext)) {
ClassifyDataFlexMetaDataFoldPoint(levelCurrent, lastStart, i, keywordlists, styler);
}
}
if (!IsASpace(ch))
visibleChars++;
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);
}
int newLineState = (styler.GetLineState(lineCurrent) & ~stateFoldMaskAll) | lineFoldStateCurrent;
styler.SetLineState(lineCurrent, newLineState);
lineCurrent++;
levelPrev = levelCurrent;
visibleChars = 0;
}
}
// If we didn't reach the EOL in previous loop, store line level and whitespace information.
// The rest will be filled in later...
int lev = levelPrev;
if (visibleChars == 0 && foldCompact)
lev |= SC_FOLDLEVELWHITEFLAG;
styler.SetLevel(lineCurrent, lev);
}
static const char * const dataflexWordListDesc[] = {
"Keywords",
"Scope open",
"Scope close",
"Operators",
0
};
LexerModule lmDataflex(SCLEX_DATAFLEX, ColouriseDataFlexDoc, "dataflex", FoldDataFlexDoc, dataflexWordListDesc);

View File

@ -0,0 +1,155 @@
// Scintilla source code edit control
/** @file LexDiff.cxx
** Lexer for diff results.
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cstdarg>
#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;
namespace {
inline bool AtEOL(Accessor &styler, Sci_PositionU i) {
return (styler[i] == '\n') ||
((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n'));
}
void ColouriseDiffLine(const char *lineBuffer, Sci_Position endLine, Accessor &styler) {
// It is needed to remember the current state to recognize starting
// comment lines before the first "diff " or "--- ". If a real
// difference starts then each line starting with ' ' is a whitespace
// otherwise it is considered a comment (Only in..., Binary file...)
if (0 == strncmp(lineBuffer, "diff ", 5)) {
styler.ColourTo(endLine, SCE_DIFF_COMMAND);
} else if (0 == strncmp(lineBuffer, "Index: ", 7)) { // For subversion's diff
styler.ColourTo(endLine, SCE_DIFF_COMMAND);
} else if (0 == strncmp(lineBuffer, "---", 3) && lineBuffer[3] != '-') {
// In a context diff, --- appears in both the header and the position markers
if (lineBuffer[3] == ' ' && atoi(lineBuffer + 4) && !strchr(lineBuffer, '/'))
styler.ColourTo(endLine, SCE_DIFF_POSITION);
else if (lineBuffer[3] == '\r' || lineBuffer[3] == '\n')
styler.ColourTo(endLine, SCE_DIFF_POSITION);
else if (lineBuffer[3] == ' ')
styler.ColourTo(endLine, SCE_DIFF_HEADER);
else
styler.ColourTo(endLine, SCE_DIFF_DELETED);
} else if (0 == strncmp(lineBuffer, "+++ ", 4)) {
// I don't know of any diff where "+++ " is a position marker, but for
// consistency, do the same as with "--- " and "*** ".
if (atoi(lineBuffer+4) && !strchr(lineBuffer, '/'))
styler.ColourTo(endLine, SCE_DIFF_POSITION);
else
styler.ColourTo(endLine, SCE_DIFF_HEADER);
} else if (0 == strncmp(lineBuffer, "====", 4)) { // For p4's diff
styler.ColourTo(endLine, SCE_DIFF_HEADER);
} else if (0 == strncmp(lineBuffer, "***", 3)) {
// In a context diff, *** appears in both the header and the position markers.
// Also ******** is a chunk header, but here it's treated as part of the
// position marker since there is no separate style for a chunk header.
if (lineBuffer[3] == ' ' && atoi(lineBuffer+4) && !strchr(lineBuffer, '/'))
styler.ColourTo(endLine, SCE_DIFF_POSITION);
else if (lineBuffer[3] == '*')
styler.ColourTo(endLine, SCE_DIFF_POSITION);
else
styler.ColourTo(endLine, SCE_DIFF_HEADER);
} else if (0 == strncmp(lineBuffer, "? ", 2)) { // For difflib
styler.ColourTo(endLine, SCE_DIFF_HEADER);
} else if (lineBuffer[0] == '@') {
styler.ColourTo(endLine, SCE_DIFF_POSITION);
} else if (lineBuffer[0] >= '0' && lineBuffer[0] <= '9') {
styler.ColourTo(endLine, SCE_DIFF_POSITION);
} else if (0 == strncmp(lineBuffer, "++", 2)) {
styler.ColourTo(endLine, SCE_DIFF_PATCH_ADD);
} else if (0 == strncmp(lineBuffer, "+-", 2)) {
styler.ColourTo(endLine, SCE_DIFF_PATCH_DELETE);
} else if (0 == strncmp(lineBuffer, "-+", 2)) {
styler.ColourTo(endLine, SCE_DIFF_REMOVED_PATCH_ADD);
} else if (0 == strncmp(lineBuffer, "--", 2)) {
styler.ColourTo(endLine, SCE_DIFF_REMOVED_PATCH_DELETE);
} else if (lineBuffer[0] == '-' || lineBuffer[0] == '<') {
styler.ColourTo(endLine, SCE_DIFF_DELETED);
} else if (lineBuffer[0] == '+' || lineBuffer[0] == '>') {
styler.ColourTo(endLine, SCE_DIFF_ADDED);
} else if (lineBuffer[0] == '!') {
styler.ColourTo(endLine, SCE_DIFF_CHANGED);
} else if (lineBuffer[0] != ' ') {
styler.ColourTo(endLine, SCE_DIFF_COMMENT);
} else {
styler.ColourTo(endLine, SCE_DIFF_DEFAULT);
}
}
void ColouriseDiffDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
std::string lineBuffer;
styler.StartAt(startPos);
styler.StartSegment(startPos);
for (Sci_PositionU i = startPos; i < startPos + length; i++) {
if (AtEOL(styler, i)) {
ColouriseDiffLine(lineBuffer.c_str(), i, styler);
lineBuffer.clear();
} else {
lineBuffer.push_back(styler[i]);
}
}
if (!lineBuffer.empty()) { // Last line does not have ending characters
ColouriseDiffLine(lineBuffer.c_str(), startPos + length - 1, styler);
}
}
void FoldDiffDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
Sci_Position curLine = styler.GetLine(startPos);
Sci_Position curLineStart = styler.LineStart(curLine);
int prevLevel = curLine > 0 ? styler.LevelAt(curLine - 1) : SC_FOLDLEVELBASE;
do {
int nextLevel = 0;
const int lineType = styler.StyleAt(curLineStart);
if (lineType == SCE_DIFF_COMMAND)
nextLevel = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
else if (lineType == SCE_DIFF_HEADER)
nextLevel = (SC_FOLDLEVELBASE + 1) | SC_FOLDLEVELHEADERFLAG;
else if (lineType == SCE_DIFF_POSITION && styler[curLineStart] != '-')
nextLevel = (SC_FOLDLEVELBASE + 2) | SC_FOLDLEVELHEADERFLAG;
else if (prevLevel & SC_FOLDLEVELHEADERFLAG)
nextLevel = (prevLevel & SC_FOLDLEVELNUMBERMASK) + 1;
else
nextLevel = prevLevel;
if ((nextLevel & SC_FOLDLEVELHEADERFLAG) && (nextLevel == prevLevel))
styler.SetLevel(curLine-1, prevLevel & ~SC_FOLDLEVELHEADERFLAG);
styler.SetLevel(curLine, nextLevel);
prevLevel = nextLevel;
curLineStart = styler.LineStart(++curLine);
} while (static_cast<Sci_Position>(startPos)+length > curLineStart);
}
const char *const emptyWordListDesc[] = {
nullptr
};
}
LexerModule lmDiff(SCLEX_DIFF, ColouriseDiffDoc, "diff", FoldDiffDoc, emptyWordListDesc);

View File

@ -0,0 +1,521 @@
// Scintilla source code edit control
/** @file LexECL.cxx
** Lexer for ECL.
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// 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>
#ifdef _MSC_VER
#pragma warning(disable: 4786)
#endif
#ifdef __BORLANDC__
// Borland C++ displays warnings in vector header without this
#pragma option -w-ccc -w-rch
#endif
#include <string>
#include <string_view>
#include <vector>
#include <map>
#include <algorithm>
#include <functional>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "PropSetSimple.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
#define SET_LOWER "abcdefghijklmnopqrstuvwxyz"
#define SET_UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define SET_DIGITS "0123456789"
using namespace Lexilla;
static bool IsSpaceEquiv(int state) {
switch (state) {
case SCE_ECL_DEFAULT:
case SCE_ECL_COMMENT:
case SCE_ECL_COMMENTLINE:
case SCE_ECL_COMMENTLINEDOC:
case SCE_ECL_COMMENTDOCKEYWORD:
case SCE_ECL_COMMENTDOCKEYWORDERROR:
case SCE_ECL_COMMENTDOC:
return true;
default:
return false;
}
}
static void ColouriseEclDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
WordList &keywords0 = *keywordlists[0];
WordList &keywords1 = *keywordlists[1];
WordList &keywords2 = *keywordlists[2];
WordList &keywords3 = *keywordlists[3]; //Value Types
WordList &keywords4 = *keywordlists[4];
WordList &keywords5 = *keywordlists[5];
WordList &keywords6 = *keywordlists[6]; //Javadoc Tags
WordList cplusplus;
cplusplus.Set("beginc endc");
bool stylingWithinPreprocessor = false;
CharacterSet setOKBeforeRE(CharacterSet::setNone, "(=,");
CharacterSet setDoxygen(CharacterSet::setLower, "$@\\&<>#{}[]");
CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true);
CharacterSet setQualified(CharacterSet::setNone, "uUxX");
int chPrevNonWhite = ' ';
int visibleChars = 0;
bool lastWordWasUUID = false;
int styleBeforeDCKeyword = SCE_ECL_DEFAULT;
bool continuationLine = false;
if (initStyle == SCE_ECL_PREPROCESSOR) {
// Set continuationLine if last character of previous line is '\'
Sci_Position lineCurrent = styler.GetLine(startPos);
if (lineCurrent > 0) {
int chBack = styler.SafeGetCharAt(startPos-1, 0);
int chBack2 = styler.SafeGetCharAt(startPos-2, 0);
int lineEndChar = '!';
if (chBack2 == '\r' && chBack == '\n') {
lineEndChar = styler.SafeGetCharAt(startPos-3, 0);
} else if (chBack == '\n' || chBack == '\r') {
lineEndChar = chBack2;
}
continuationLine = lineEndChar == '\\';
}
}
// look back to set chPrevNonWhite properly for better regex colouring
if (startPos > 0) {
Sci_Position back = startPos;
while (--back && IsSpaceEquiv(styler.StyleAt(back)))
;
if (styler.StyleAt(back) == SCE_ECL_OPERATOR) {
chPrevNonWhite = styler.SafeGetCharAt(back);
}
}
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
if (sc.atLineStart) {
if (sc.state == SCE_ECL_STRING) {
// Prevent SCE_ECL_STRINGEOL from leaking back to previous line which
// ends with a line continuation by locking in the state upto this position.
sc.SetState(SCE_ECL_STRING);
}
// Reset states to begining of colourise so no surprises
// if different sets of lines lexed.
visibleChars = 0;
lastWordWasUUID = false;
}
// 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();
}
continuationLine = true;
continue;
}
}
// Determine if the current state should terminate.
switch (sc.state) {
case SCE_ECL_ADDED:
case SCE_ECL_DELETED:
case SCE_ECL_CHANGED:
case SCE_ECL_MOVED:
if (sc.atLineStart)
sc.SetState(SCE_ECL_DEFAULT);
break;
case SCE_ECL_OPERATOR:
sc.SetState(SCE_ECL_DEFAULT);
break;
case SCE_ECL_NUMBER:
// We accept almost anything because of hex. and number suffixes
if (!setWord.Contains(sc.ch)) {
sc.SetState(SCE_ECL_DEFAULT);
}
break;
case SCE_ECL_IDENTIFIER:
if (!setWord.Contains(sc.ch) || (sc.ch == '.')) {
char s[1000];
sc.GetCurrentLowered(s, sizeof(s));
if (keywords0.InList(s)) {
lastWordWasUUID = strcmp(s, "uuid") == 0;
sc.ChangeState(SCE_ECL_WORD0);
} else if (keywords1.InList(s)) {
sc.ChangeState(SCE_ECL_WORD1);
} else if (keywords2.InList(s)) {
sc.ChangeState(SCE_ECL_WORD2);
} else if (keywords4.InList(s)) {
sc.ChangeState(SCE_ECL_WORD4);
} else if (keywords5.InList(s)) {
sc.ChangeState(SCE_ECL_WORD5);
}
else //Data types are of from KEYWORD##
{
int i = static_cast<int>(strlen(s)) - 1;
while(i >= 0 && (isdigit(s[i]) || s[i] == '_'))
--i;
char s2[1000];
strncpy(s2, s, i + 1);
s2[i + 1] = 0;
if (keywords3.InList(s2)) {
sc.ChangeState(SCE_ECL_WORD3);
}
}
sc.SetState(SCE_ECL_DEFAULT);
}
break;
case SCE_ECL_PREPROCESSOR:
if (sc.atLineStart && !continuationLine) {
sc.SetState(SCE_ECL_DEFAULT);
} else if (stylingWithinPreprocessor) {
if (IsASpace(sc.ch)) {
sc.SetState(SCE_ECL_DEFAULT);
}
} else {
if (sc.Match('/', '*') || sc.Match('/', '/')) {
sc.SetState(SCE_ECL_DEFAULT);
}
}
break;
case SCE_ECL_COMMENT:
if (sc.Match('*', '/')) {
sc.Forward();
sc.ForwardSetState(SCE_ECL_DEFAULT);
}
break;
case SCE_ECL_COMMENTDOC:
if (sc.Match('*', '/')) {
sc.Forward();
sc.ForwardSetState(SCE_ECL_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))) {
styleBeforeDCKeyword = SCE_ECL_COMMENTDOC;
sc.SetState(SCE_ECL_COMMENTDOCKEYWORD);
}
}
break;
case SCE_ECL_COMMENTLINE:
if (sc.atLineStart) {
sc.SetState(SCE_ECL_DEFAULT);
}
break;
case SCE_ECL_COMMENTLINEDOC:
if (sc.atLineStart) {
sc.SetState(SCE_ECL_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 == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) {
styleBeforeDCKeyword = SCE_ECL_COMMENTLINEDOC;
sc.SetState(SCE_ECL_COMMENTDOCKEYWORD);
}
}
break;
case SCE_ECL_COMMENTDOCKEYWORD:
if ((styleBeforeDCKeyword == SCE_ECL_COMMENTDOC) && sc.Match('*', '/')) {
sc.ChangeState(SCE_ECL_COMMENTDOCKEYWORDERROR);
sc.Forward();
sc.ForwardSetState(SCE_ECL_DEFAULT);
} else if (!setDoxygen.Contains(sc.ch)) {
char s[1000];
sc.GetCurrentLowered(s, sizeof(s));
if (!IsASpace(sc.ch) || !keywords6.InList(s+1)) {
sc.ChangeState(SCE_ECL_COMMENTDOCKEYWORDERROR);
}
sc.SetState(styleBeforeDCKeyword);
}
break;
case SCE_ECL_STRING:
if (sc.atLineEnd) {
sc.ChangeState(SCE_ECL_STRINGEOL);
} else if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_ECL_DEFAULT);
}
break;
case SCE_ECL_CHARACTER:
if (sc.atLineEnd) {
sc.ChangeState(SCE_ECL_STRINGEOL);
} else if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\'') {
sc.ForwardSetState(SCE_ECL_DEFAULT);
}
break;
case SCE_ECL_REGEX:
if (sc.atLineStart) {
sc.SetState(SCE_ECL_DEFAULT);
} else if (sc.ch == '/') {
sc.Forward();
while ((sc.ch < 0x80) && islower(sc.ch))
sc.Forward(); // gobble regex flags
sc.SetState(SCE_ECL_DEFAULT);
} else if (sc.ch == '\\') {
// Gobble up the quoted character
if (sc.chNext == '\\' || sc.chNext == '/') {
sc.Forward();
}
}
break;
case SCE_ECL_STRINGEOL:
if (sc.atLineStart) {
sc.SetState(SCE_ECL_DEFAULT);
}
break;
case SCE_ECL_VERBATIM:
if (sc.ch == '\"') {
if (sc.chNext == '\"') {
sc.Forward();
} else {
sc.ForwardSetState(SCE_ECL_DEFAULT);
}
}
break;
case SCE_ECL_UUID:
if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
sc.SetState(SCE_ECL_DEFAULT);
}
break;
}
// Determine if a new state should be entered.
Sci_Position lineCurrent = styler.GetLine(sc.currentPos);
int lineState = styler.GetLineState(lineCurrent);
if (sc.state == SCE_ECL_DEFAULT) {
if (lineState) {
sc.SetState(lineState);
}
else if (sc.Match('@', '\"')) {
sc.SetState(SCE_ECL_VERBATIM);
sc.Forward();
} else if (setQualified.Contains(sc.ch) && sc.chNext == '\'') {
sc.SetState(SCE_ECL_CHARACTER);
sc.Forward();
} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
if (lastWordWasUUID) {
sc.SetState(SCE_ECL_UUID);
lastWordWasUUID = false;
} else {
sc.SetState(SCE_ECL_NUMBER);
}
} else if (setWordStart.Contains(sc.ch) || (sc.ch == '@')) {
if (lastWordWasUUID) {
sc.SetState(SCE_ECL_UUID);
lastWordWasUUID = false;
} else {
sc.SetState(SCE_ECL_IDENTIFIER);
}
} else if (sc.Match('/', '*')) {
if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style
sc.SetState(SCE_ECL_COMMENTDOC);
} else {
sc.SetState(SCE_ECL_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_ECL_COMMENTLINEDOC);
else
sc.SetState(SCE_ECL_COMMENTLINE);
} else if (sc.ch == '/' && setOKBeforeRE.Contains(chPrevNonWhite)) {
sc.SetState(SCE_ECL_REGEX); // JavaScript's RegEx
// } else if (sc.ch == '\"') {
// sc.SetState(SCE_ECL_STRING);
} else if (sc.ch == '\'') {
sc.SetState(SCE_ECL_CHARACTER);
} else if (sc.ch == '#' && visibleChars == 0) {
// Preprocessor commands are alone on their line
sc.SetState(SCE_ECL_PREPROCESSOR);
// Skip whitespace between # and preprocessor word
do {
sc.Forward();
} while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
if (sc.atLineEnd) {
sc.SetState(SCE_ECL_DEFAULT);
}
} else if (isoperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_ECL_OPERATOR);
}
}
if (!IsASpace(sc.ch) && !IsSpaceEquiv(sc.state)) {
chPrevNonWhite = sc.ch;
visibleChars++;
}
continuationLine = false;
}
sc.Complete();
}
static bool IsStreamCommentStyle(int style) {
return style == SCE_ECL_COMMENT ||
style == SCE_ECL_COMMENTDOC ||
style == SCE_ECL_COMMENTDOCKEYWORD ||
style == SCE_ECL_COMMENTDOCKEYWORDERROR;
}
static bool MatchNoCase(Accessor & styler, Sci_PositionU & pos, const char *s) {
Sci_Position i=0;
for (; *s; i++) {
char compare_char = tolower(*s);
char styler_char = tolower(styler.SafeGetCharAt(pos+i));
if (compare_char != styler_char)
return false;
s++;
}
pos+=i-1;
return true;
}
// 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 FoldEclDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *[], Accessor &styler) {
bool foldComment = true;
bool foldPreprocessor = true;
bool foldCompact = true;
bool foldAtElse = true;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position 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 (Sci_PositionU 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) && (stylePrev != SCE_ECL_COMMENTLINEDOC)) {
levelNext++;
} else if (!IsStreamCommentStyle(styleNext) && (styleNext != SCE_ECL_COMMENTLINEDOC) && !atEOL) {
// Comments don't end at end of line and the next character may be unstyled.
levelNext--;
}
}
if (foldComment && (style == SCE_ECL_COMMENTLINE)) {
if ((ch == '/') && (chNext == '/')) {
char chNext2 = styler.SafeGetCharAt(i + 2);
if (chNext2 == '{') {
levelNext++;
} else if (chNext2 == '}') {
levelNext--;
}
}
}
if (foldPreprocessor && (style == SCE_ECL_PREPROCESSOR)) {
if (ch == '#') {
Sci_PositionU j = i + 1;
while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
j++;
}
if (MatchNoCase(styler, j, "region") || MatchNoCase(styler, j, "if")) {
levelNext++;
} else if (MatchNoCase(styler, j, "endregion") || MatchNoCase(styler, j, "end")) {
levelNext--;
}
}
}
if (style == SCE_ECL_OPERATOR) {
if (ch == '{') {
// Measure the minimum before a '{' to allow
// folding on "} else {"
if (levelMinCurrent > levelNext) {
levelMinCurrent = levelNext;
}
levelNext++;
} else if (ch == '}') {
levelNext--;
}
}
if (style == SCE_ECL_WORD2) {
if (MatchNoCase(styler, i, "record") || MatchNoCase(styler, i, "transform") || MatchNoCase(styler, i, "type") || MatchNoCase(styler, i, "function") ||
MatchNoCase(styler, i, "module") || MatchNoCase(styler, i, "service") || MatchNoCase(styler, i, "interface") || MatchNoCase(styler, i, "ifblock") ||
MatchNoCase(styler, i, "macro") || MatchNoCase(styler, i, "beginc++")) {
levelNext++;
} else if (MatchNoCase(styler, i, "endmacro") || MatchNoCase(styler, i, "endc++") || MatchNoCase(styler, i, "end")) {
levelNext--;
}
}
if (atEOL || (i == endPos-1)) {
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;
if (atEOL && (i == static_cast<Sci_PositionU>(styler.Length()-1))) {
// There is an empty line at end of file so give it same level and empty
styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
}
visibleChars = 0;
}
if (!IsASpace(ch))
visibleChars++;
}
}
static const char * const EclWordListDesc[] = {
"Keywords",
0
};
LexerModule lmECL(
SCLEX_ECL,
ColouriseEclDoc,
"ecl",
FoldEclDoc,
EclWordListDesc);

View File

@ -0,0 +1,405 @@
// Scintilla Lexer for EDIFACT
// @file LexEDIFACT.cxx
// Written by Iain Clarke, IMCSoft & Inobiz AB.
// EDIFACT documented here: https://www.unece.org/cefact/edifact/welcome.html
// and more readably here: https://en.wikipedia.org/wiki/EDIFACT
// This code is subject to the same license terms as the rest of the scintilla project:
// The License.txt file describes the conditions under which this software may be distributed.
//
// Header order must match order in scripts/HeaderOrder.txt
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cctype>
#include <string>
#include <string_view>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "LexAccessor.h"
#include "LexerModule.h"
#include "DefaultLexer.h"
using namespace Scintilla;
using namespace Lexilla;
class LexerEDIFACT : public DefaultLexer
{
public:
LexerEDIFACT();
virtual ~LexerEDIFACT() {} // virtual destructor, as we inherit from ILexer
static ILexer5 *Factory() {
return new LexerEDIFACT;
}
int SCI_METHOD Version() const override
{
return lvRelease5;
}
void SCI_METHOD Release() override
{
delete this;
}
const char * SCI_METHOD PropertyNames() override
{
return "fold\nlexer.edifact.highlight.un.all";
}
int SCI_METHOD PropertyType(const char *) override
{
return SC_TYPE_BOOLEAN; // Only one property!
}
const char * SCI_METHOD DescribeProperty(const char *name) override
{
if (!strcmp(name, "fold"))
return "Whether to apply folding to document or not";
if (!strcmp(name, "lexer.edifact.highlight.un.all"))
return "Whether to apply UN* highlighting to all UN segments, or just to UNH";
return NULL;
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override
{
if (!strcmp(key, "fold"))
{
m_bFold = strcmp(val, "0") ? true : false;
return 0;
}
if (!strcmp(key, "lexer.edifact.highlight.un.all")) // GetProperty
{
m_bHighlightAllUN = strcmp(val, "0") ? true : false;
return 0;
}
return -1;
}
const char * SCI_METHOD PropertyGet(const char *key) override
{
m_lastPropertyValue = "";
if (!strcmp(key, "fold"))
{
m_lastPropertyValue = m_bFold ? "1" : "0";
}
if (!strcmp(key, "lexer.edifact.highlight.un.all")) // GetProperty
{
m_lastPropertyValue = m_bHighlightAllUN ? "1" : "0";
}
return m_lastPropertyValue.c_str();
}
const char * SCI_METHOD DescribeWordListSets() override
{
return NULL;
}
Sci_Position SCI_METHOD WordListSet(int, const char *) override
{
return -1;
}
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void * SCI_METHOD PrivateCall(int, void *) override
{
return NULL;
}
protected:
Sci_Position InitialiseFromUNA(IDocument *pAccess, Sci_PositionU MaxLength);
Sci_Position FindPreviousEnd(IDocument *pAccess, Sci_Position startPos) const;
Sci_Position ForwardPastWhitespace(IDocument *pAccess, Sci_Position startPos, Sci_Position MaxLength) const;
int DetectSegmentHeader(char SegmentHeader[3]) const;
bool m_bFold;
// property lexer.edifact.highlight.un.all
// Set to 0 to highlight only UNA segments, or 1 to highlight all UNx segments.
bool m_bHighlightAllUN;
char m_chComponent;
char m_chData;
char m_chDecimal;
char m_chRelease;
char m_chSegment;
std::string m_lastPropertyValue;
};
LexerModule lmEDIFACT(SCLEX_EDIFACT, LexerEDIFACT::Factory, "edifact");
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LexerEDIFACT::LexerEDIFACT() : DefaultLexer("edifact", SCLEX_EDIFACT)
{
m_bFold = false;
m_bHighlightAllUN = false;
m_chComponent = ':';
m_chData = '+';
m_chDecimal = '.';
m_chRelease = '?';
m_chSegment = '\'';
}
void LexerEDIFACT::Lex(Sci_PositionU startPos, Sci_Position length, int, IDocument *pAccess)
{
Sci_PositionU posFinish = startPos + length;
InitialiseFromUNA(pAccess, posFinish);
// Look backwards for a ' or a document beginning
Sci_PositionU posCurrent = FindPreviousEnd(pAccess, startPos);
// And jump past the ' if this was not the beginning of the document
if (posCurrent != 0)
posCurrent++;
// Style buffer, so we're not issuing loads of notifications
LexAccessor styler (pAccess);
pAccess->StartStyling(posCurrent);
styler.StartSegment(posCurrent);
Sci_Position posSegmentStart = -1;
while ((posCurrent < posFinish) && (posSegmentStart == -1))
{
posCurrent = ForwardPastWhitespace(pAccess, posCurrent, posFinish);
// Mark whitespace as default
styler.ColourTo(posCurrent - 1, SCE_EDI_DEFAULT);
if (posCurrent >= posFinish)
break;
// Does is start with 3 charaters? ie, UNH
char SegmentHeader[4] = { 0 };
pAccess->GetCharRange(SegmentHeader, posCurrent, 3);
int SegmentStyle = DetectSegmentHeader(SegmentHeader);
if (SegmentStyle == SCE_EDI_BADSEGMENT)
break;
if (SegmentStyle == SCE_EDI_UNA)
{
posCurrent += 9;
styler.ColourTo(posCurrent - 1, SCE_EDI_UNA); // UNA
continue;
}
posSegmentStart = posCurrent;
posCurrent += 3;
styler.ColourTo(posCurrent - 1, SegmentStyle); // UNH etc
// Colour in the rest of the segment
for (char c; posCurrent < posFinish; posCurrent++)
{
pAccess->GetCharRange(&c, posCurrent, 1);
if (c == m_chRelease) // ? escape character, check first, in case of ?'
posCurrent++;
else if (c == m_chSegment) // '
{
// Make sure the whole segment is on one line. styler won't let us go back in time, so we'll settle for marking the ' as bad.
Sci_Position lineSegmentStart = pAccess->LineFromPosition(posSegmentStart);
Sci_Position lineSegmentEnd = pAccess->LineFromPosition(posCurrent);
if (lineSegmentStart == lineSegmentEnd)
styler.ColourTo(posCurrent, SCE_EDI_SEGMENTEND);
else
styler.ColourTo(posCurrent, SCE_EDI_BADSEGMENT);
posSegmentStart = -1;
posCurrent++;
break;
}
else if (c == m_chComponent) // :
styler.ColourTo(posCurrent, SCE_EDI_SEP_COMPOSITE);
else if (c == m_chData) // +
styler.ColourTo(posCurrent, SCE_EDI_SEP_ELEMENT);
else
styler.ColourTo(posCurrent, SCE_EDI_DEFAULT);
}
}
styler.Flush();
if (posSegmentStart == -1)
return;
pAccess->StartStyling(posSegmentStart);
pAccess->SetStyleFor(posFinish - posSegmentStart, SCE_EDI_BADSEGMENT);
}
void LexerEDIFACT::Fold(Sci_PositionU startPos, Sci_Position length, int, IDocument *pAccess)
{
if (!m_bFold)
return;
Sci_PositionU endPos = startPos + length;
startPos = FindPreviousEnd(pAccess, startPos);
char c;
char SegmentHeader[4] = { 0 };
bool AwaitingSegment = true;
Sci_PositionU currLine = pAccess->LineFromPosition(startPos);
int levelCurrentStyle = SC_FOLDLEVELBASE;
if (currLine > 0)
levelCurrentStyle = pAccess->GetLevel(currLine - 1); // bottom 12 bits are level
int indentCurrent = levelCurrentStyle & SC_FOLDLEVELNUMBERMASK;
int indentNext = indentCurrent;
while (startPos < endPos)
{
pAccess->GetCharRange(&c, startPos, 1);
switch (c)
{
case '\t':
case '\r':
case ' ':
startPos++;
continue;
case '\n':
currLine = pAccess->LineFromPosition(startPos);
pAccess->SetLevel(currLine, levelCurrentStyle | indentCurrent);
startPos++;
levelCurrentStyle = SC_FOLDLEVELBASE;
indentCurrent = indentNext;
continue;
}
if (c == m_chRelease)
{
startPos += 2;
continue;
}
if (c == m_chSegment)
{
AwaitingSegment = true;
startPos++;
continue;
}
if (!AwaitingSegment)
{
startPos++;
continue;
}
// Segment!
pAccess->GetCharRange(SegmentHeader, startPos, 3);
if (SegmentHeader[0] != 'U' || SegmentHeader[1] != 'N')
{
startPos++;
continue;
}
AwaitingSegment = false;
switch (SegmentHeader[2])
{
case 'H':
case 'G':
indentNext++;
levelCurrentStyle = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
break;
case 'T':
case 'E':
if (indentNext > 0)
indentNext--;
break;
}
startPos += 3;
}
}
Sci_Position LexerEDIFACT::InitialiseFromUNA(IDocument *pAccess, Sci_PositionU MaxLength)
{
MaxLength -= 9; // drop 9 chars, to give us room for UNA:+.? '
Sci_PositionU startPos = 0;
startPos += ForwardPastWhitespace(pAccess, 0, MaxLength);
if (startPos < MaxLength)
{
char bufUNA[9];
pAccess->GetCharRange(bufUNA, startPos, 9);
// Check it's UNA segment
if (!memcmp(bufUNA, "UNA", 3))
{
m_chComponent = bufUNA[3];
m_chData = bufUNA[4];
m_chDecimal = bufUNA[5];
m_chRelease = bufUNA[6];
// bufUNA [7] should be space - reserved.
m_chSegment = bufUNA[8];
return 0; // success!
}
}
// We failed to find a UNA, so drop to defaults
m_chComponent = ':';
m_chData = '+';
m_chDecimal = '.';
m_chRelease = '?';
m_chSegment = '\'';
return -1;
}
Sci_Position LexerEDIFACT::ForwardPastWhitespace(IDocument *pAccess, Sci_Position startPos, Sci_Position MaxLength) const
{
char c;
while (startPos < MaxLength)
{
pAccess->GetCharRange(&c, startPos, 1);
switch (c)
{
case '\t':
case '\r':
case '\n':
case ' ':
break;
default:
return startPos;
}
startPos++;
}
return MaxLength;
}
int LexerEDIFACT::DetectSegmentHeader(char SegmentHeader[3]) const
{
if (
SegmentHeader[0] < 'A' || SegmentHeader[0] > 'Z' ||
SegmentHeader[1] < 'A' || SegmentHeader[1] > 'Z' ||
SegmentHeader[2] < 'A' || SegmentHeader[2] > 'Z')
return SCE_EDI_BADSEGMENT;
if (!memcmp(SegmentHeader, "UNA", 3))
return SCE_EDI_UNA;
if (m_bHighlightAllUN && !memcmp(SegmentHeader, "UN", 2))
return SCE_EDI_UNH;
else if (!memcmp(SegmentHeader, "UNH", 3))
return SCE_EDI_UNH;
else if (!memcmp(SegmentHeader, "UNG", 3))
return SCE_EDI_UNH;
return SCE_EDI_SEGMENTSTART;
}
// Look backwards for a ' or a document beginning
Sci_Position LexerEDIFACT::FindPreviousEnd(IDocument *pAccess, Sci_Position startPos) const
{
for (char c; startPos > 0; startPos--)
{
pAccess->GetCharRange(&c, startPos, 1);
if (c == m_chSegment)
return startPos;
}
// We didn't find a ', so just go with the beginning
return 0;
}

View File

@ -0,0 +1,277 @@
// Scintilla source code edit control
/** @file LexEScript.cxx
** Lexer for ESCRIPT
**/
// Copyright 2003 by Patrizio Bekerle (patrizio@bekerle.com)
#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;
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}
static inline bool IsAWordStart(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_');
}
static void ColouriseESCRIPTDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
WordList &keywords = *keywordlists[0];
WordList &keywords2 = *keywordlists[1];
WordList &keywords3 = *keywordlists[2];
// Do not leak onto next line
/*if (initStyle == SCE_ESCRIPT_STRINGEOL)
initStyle = SCE_ESCRIPT_DEFAULT;*/
StyleContext sc(startPos, length, initStyle, styler);
bool caseSensitive = styler.GetPropertyInt("escript.case.sensitive", 0) != 0;
for (; sc.More(); sc.Forward()) {
/*if (sc.atLineStart && (sc.state == SCE_ESCRIPT_STRING)) {
// Prevent SCE_ESCRIPT_STRINGEOL from leaking back to previous line
sc.SetState(SCE_ESCRIPT_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_ESCRIPT_OPERATOR || sc.state == SCE_ESCRIPT_BRACE) {
sc.SetState(SCE_ESCRIPT_DEFAULT);
} else if (sc.state == SCE_ESCRIPT_NUMBER) {
if (!IsADigit(sc.ch) || sc.ch != '.') {
sc.SetState(SCE_ESCRIPT_DEFAULT);
}
} else if (sc.state == SCE_ESCRIPT_IDENTIFIER) {
if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
char s[100];
if (caseSensitive) {
sc.GetCurrent(s, sizeof(s));
} else {
sc.GetCurrentLowered(s, sizeof(s));
}
// sc.GetCurrentLowered(s, sizeof(s));
if (keywords.InList(s)) {
sc.ChangeState(SCE_ESCRIPT_WORD);
} else if (keywords2.InList(s)) {
sc.ChangeState(SCE_ESCRIPT_WORD2);
} else if (keywords3.InList(s)) {
sc.ChangeState(SCE_ESCRIPT_WORD3);
// sc.state = SCE_ESCRIPT_IDENTIFIER;
}
sc.SetState(SCE_ESCRIPT_DEFAULT);
}
} else if (sc.state == SCE_ESCRIPT_COMMENT) {
if (sc.Match('*', '/')) {
sc.Forward();
sc.ForwardSetState(SCE_ESCRIPT_DEFAULT);
}
} else if (sc.state == SCE_ESCRIPT_COMMENTDOC) {
if (sc.Match('*', '/')) {
sc.Forward();
sc.ForwardSetState(SCE_ESCRIPT_DEFAULT);
}
} else if (sc.state == SCE_ESCRIPT_COMMENTLINE) {
if (sc.atLineEnd) {
sc.SetState(SCE_ESCRIPT_DEFAULT);
}
} else if (sc.state == SCE_ESCRIPT_STRING) {
if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_ESCRIPT_DEFAULT);
}
}
// Determine if a new state should be entered.
if (sc.state == SCE_ESCRIPT_DEFAULT) {
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_ESCRIPT_NUMBER);
} else if (IsAWordStart(sc.ch) || (sc.ch == '#')) {
sc.SetState(SCE_ESCRIPT_IDENTIFIER);
} else if (sc.Match('/', '*')) {
sc.SetState(SCE_ESCRIPT_COMMENT);
sc.Forward(); // Eat the * so it isn't used for the end of the comment
} else if (sc.Match('/', '/')) {
sc.SetState(SCE_ESCRIPT_COMMENTLINE);
} else if (sc.ch == '\"') {
sc.SetState(SCE_ESCRIPT_STRING);
//} else if (isoperator(static_cast<char>(sc.ch))) {
} else if (sc.ch == '+' || sc.ch == '-' || sc.ch == '*' || sc.ch == '/' || sc.ch == '=' || sc.ch == '<' || sc.ch == '>' || sc.ch == '&' || sc.ch == '|' || sc.ch == '!' || sc.ch == '?' || sc.ch == ':') {
sc.SetState(SCE_ESCRIPT_OPERATOR);
} else if (sc.ch == '{' || sc.ch == '}') {
sc.SetState(SCE_ESCRIPT_BRACE);
}
}
}
sc.Complete();
}
static int classifyFoldPointESCRIPT(const char* s, const char* prevWord) {
int lev = 0;
if (strcmp(prevWord, "end") == 0) return lev;
if ((strcmp(prevWord, "else") == 0 && strcmp(s, "if") == 0) || strcmp(s, "elseif") == 0)
return -1;
if (strcmp(s, "for") == 0 || strcmp(s, "foreach") == 0
|| strcmp(s, "program") == 0 || strcmp(s, "function") == 0
|| strcmp(s, "while") == 0 || strcmp(s, "case") == 0
|| strcmp(s, "if") == 0 ) {
lev = 1;
} else if ( strcmp(s, "endfor") == 0 || strcmp(s, "endforeach") == 0
|| strcmp(s, "endprogram") == 0 || strcmp(s, "endfunction") == 0
|| strcmp(s, "endwhile") == 0 || strcmp(s, "endcase") == 0
|| strcmp(s, "endif") == 0 ) {
lev = -1;
}
return lev;
}
static bool IsStreamCommentStyle(int style) {
return style == SCE_ESCRIPT_COMMENT ||
style == SCE_ESCRIPT_COMMENTDOC ||
style == SCE_ESCRIPT_COMMENTLINE;
}
static void FoldESCRIPTDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[], Accessor &styler) {
//~ bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
// Do not know how to fold the comment at the moment.
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
bool foldComment = true;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
int style = initStyle;
Sci_Position lastStart = 0;
char prevWord[32] = "";
for (Sci_PositionU 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)) {
levelCurrent++;
} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
// Comments don't end at end of line and the next character may be unstyled.
levelCurrent--;
}
}
if (foldComment && (style == SCE_ESCRIPT_COMMENTLINE)) {
if ((ch == '/') && (chNext == '/')) {
char chNext2 = styler.SafeGetCharAt(i + 2);
if (chNext2 == '{') {
levelCurrent++;
} else if (chNext2 == '}') {
levelCurrent--;
}
}
}
if (stylePrev == SCE_ESCRIPT_DEFAULT && style == SCE_ESCRIPT_WORD3)
{
// Store last word start point.
lastStart = i;
}
if (style == SCE_ESCRIPT_WORD3) {
if(iswordchar(ch) && !iswordchar(chNext)) {
char s[32];
Sci_PositionU j;
for(j = 0; ( j < 31 ) && ( j < i-lastStart+1 ); j++) {
s[j] = static_cast<char>(tolower(styler[lastStart + j]));
}
s[j] = '\0';
levelCurrent += classifyFoldPointESCRIPT(s, prevWord);
strcpy(prevWord, s);
}
}
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;
strcpy(prevWord, "");
}
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 ESCRIPTWordLists[] = {
"Primary keywords and identifiers",
"Intrinsic functions",
"Extended and user defined functions",
0,
};
LexerModule lmESCRIPT(SCLEX_ESCRIPT, ColouriseESCRIPTDoc, "escript", FoldESCRIPTDoc, ESCRIPTWordLists);

View File

@ -0,0 +1,242 @@
// Scintilla source code edit control
/** @file LexEiffel.cxx
** Lexer for Eiffel.
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// 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;
static inline bool isEiffelOperator(unsigned int ch) {
// '.' left out as it is used to make up numbers
return ch == '*' || ch == '/' || ch == '\\' || ch == '-' || ch == '+' ||
ch == '(' || ch == ')' || ch == '=' ||
ch == '{' || ch == '}' || ch == '~' ||
ch == '[' || ch == ']' || ch == ';' ||
ch == '<' || ch == '>' || ch == ',' ||
ch == '.' || ch == '^' || ch == '%' || ch == ':' ||
ch == '!' || ch == '@' || ch == '?';
}
static inline bool IsAWordChar(unsigned int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_');
}
static inline bool IsAWordStart(unsigned int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_');
}
static void ColouriseEiffelDoc(Sci_PositionU startPos,
Sci_Position length,
int initStyle,
WordList *keywordlists[],
Accessor &styler) {
WordList &keywords = *keywordlists[0];
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
if (sc.state == SCE_EIFFEL_STRINGEOL) {
if (sc.ch != '\r' && sc.ch != '\n') {
sc.SetState(SCE_EIFFEL_DEFAULT);
}
} else if (sc.state == SCE_EIFFEL_OPERATOR) {
sc.SetState(SCE_EIFFEL_DEFAULT);
} else if (sc.state == SCE_EIFFEL_WORD) {
if (!IsAWordChar(sc.ch)) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
if (!keywords.InList(s)) {
sc.ChangeState(SCE_EIFFEL_IDENTIFIER);
}
sc.SetState(SCE_EIFFEL_DEFAULT);
}
} else if (sc.state == SCE_EIFFEL_NUMBER) {
if (!IsAWordChar(sc.ch)) {
sc.SetState(SCE_EIFFEL_DEFAULT);
}
} else if (sc.state == SCE_EIFFEL_COMMENTLINE) {
if (sc.ch == '\r' || sc.ch == '\n') {
sc.SetState(SCE_EIFFEL_DEFAULT);
}
} else if (sc.state == SCE_EIFFEL_STRING) {
if (sc.ch == '%') {
sc.Forward();
} else if (sc.ch == '\"') {
sc.Forward();
sc.SetState(SCE_EIFFEL_DEFAULT);
}
} else if (sc.state == SCE_EIFFEL_CHARACTER) {
if (sc.ch == '\r' || sc.ch == '\n') {
sc.SetState(SCE_EIFFEL_STRINGEOL);
} else if (sc.ch == '%') {
sc.Forward();
} else if (sc.ch == '\'') {
sc.Forward();
sc.SetState(SCE_EIFFEL_DEFAULT);
}
}
if (sc.state == SCE_EIFFEL_DEFAULT) {
if (sc.ch == '-' && sc.chNext == '-') {
sc.SetState(SCE_EIFFEL_COMMENTLINE);
} else if (sc.ch == '\"') {
sc.SetState(SCE_EIFFEL_STRING);
} else if (sc.ch == '\'') {
sc.SetState(SCE_EIFFEL_CHARACTER);
} else if (IsADigit(sc.ch) || (sc.ch == '.')) {
sc.SetState(SCE_EIFFEL_NUMBER);
} else if (IsAWordStart(sc.ch)) {
sc.SetState(SCE_EIFFEL_WORD);
} else if (isEiffelOperator(sc.ch)) {
sc.SetState(SCE_EIFFEL_OPERATOR);
}
}
}
sc.Complete();
}
static bool IsEiffelComment(Accessor &styler, Sci_Position pos, Sci_Position len) {
return len>1 && styler[pos]=='-' && styler[pos+1]=='-';
}
static void FoldEiffelDocIndent(Sci_PositionU startPos, Sci_Position length, int,
WordList *[], Accessor &styler) {
Sci_Position lengthDoc = startPos + length;
// Backtrack to previous line in case need to fix its fold status
Sci_Position lineCurrent = styler.GetLine(startPos);
if (startPos > 0) {
if (lineCurrent > 0) {
lineCurrent--;
startPos = styler.LineStart(lineCurrent);
}
}
int spaceFlags = 0;
int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsEiffelComment);
char chNext = styler[startPos];
for (Sci_Position i = startPos; i < lengthDoc; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) {
int lev = indentCurrent;
int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsEiffelComment);
if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
// Only non whitespace lines can be headers
if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
lev |= SC_FOLDLEVELHEADERFLAG;
} else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
// Line after is blank so check the next - maybe should continue further?
int spaceFlags2 = 0;
int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsEiffelComment);
if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
lev |= SC_FOLDLEVELHEADERFLAG;
}
}
}
indentCurrent = indentNext;
styler.SetLevel(lineCurrent, lev);
lineCurrent++;
}
}
}
static void FoldEiffelDocKeyWords(Sci_PositionU startPos, Sci_Position length, int /* initStyle */, WordList *[],
Accessor &styler) {
Sci_PositionU lengthDoc = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
int stylePrev = 0;
int styleNext = styler.StyleAt(startPos);
// lastDeferred should be determined by looking back to last keyword in case
// the "deferred" is on a line before "class"
bool lastDeferred = false;
for (Sci_PositionU 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 ((stylePrev != SCE_EIFFEL_WORD) && (style == SCE_EIFFEL_WORD)) {
char s[20];
Sci_PositionU j = 0;
while ((j < (sizeof(s) - 1)) && (iswordchar(styler[i + j]))) {
s[j] = styler[i + j];
j++;
}
s[j] = '\0';
if (
(strcmp(s, "check") == 0) ||
(strcmp(s, "debug") == 0) ||
(strcmp(s, "deferred") == 0) ||
(strcmp(s, "do") == 0) ||
(strcmp(s, "from") == 0) ||
(strcmp(s, "if") == 0) ||
(strcmp(s, "inspect") == 0) ||
(strcmp(s, "once") == 0)
)
levelCurrent++;
if (!lastDeferred && (strcmp(s, "class") == 0))
levelCurrent++;
if (strcmp(s, "end") == 0)
levelCurrent--;
lastDeferred = strcmp(s, "deferred") == 0;
}
if (atEOL) {
int lev = levelPrev;
if (visibleChars == 0)
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++;
stylePrev = style;
}
// 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 eiffelWordListDesc[] = {
"Keywords",
0
};
LexerModule lmEiffel(SCLEX_EIFFEL, ColouriseEiffelDoc, "eiffel", FoldEiffelDocIndent, eiffelWordListDesc);
LexerModule lmEiffelkw(SCLEX_EIFFELKW, ColouriseEiffelDoc, "eiffelkw", FoldEiffelDocKeyWords, eiffelWordListDesc);

View File

@ -0,0 +1,631 @@
// Scintilla source code edit control
// Encoding: UTF-8
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
/** @file LexErlang.cxx
** Lexer for Erlang.
** Enhanced by Etienne 'Lenain' Girondel (lenaing@gmail.com)
** Originally wrote by Peter-Henry Mander,
** based on Matlab lexer by José Fonseca.
**/
#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;
static int is_radix(int radix, int ch) {
int digit;
if (36 < radix || 2 > radix)
return 0;
if (isdigit(ch)) {
digit = ch - '0';
} else if (isalnum(ch)) {
digit = toupper(ch) - 'A' + 10;
} else {
return 0;
}
return (digit < radix);
}
typedef enum {
STATE_NULL,
COMMENT,
COMMENT_FUNCTION,
COMMENT_MODULE,
COMMENT_DOC,
COMMENT_DOC_MACRO,
ATOM_UNQUOTED,
ATOM_QUOTED,
NODE_NAME_UNQUOTED,
NODE_NAME_QUOTED,
MACRO_START,
MACRO_UNQUOTED,
MACRO_QUOTED,
RECORD_START,
RECORD_UNQUOTED,
RECORD_QUOTED,
NUMERAL_START,
NUMERAL_BASE_VALUE,
NUMERAL_FLOAT,
NUMERAL_EXPONENT,
PREPROCESSOR
} atom_parse_state_t;
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (ch != ' ') && (isalnum(ch) || ch == '_');
}
static void ColouriseErlangDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler) {
StyleContext sc(startPos, length, initStyle, styler);
WordList &reservedWords = *keywordlists[0];
WordList &erlangBIFs = *keywordlists[1];
WordList &erlangPreproc = *keywordlists[2];
WordList &erlangModulesAtt = *keywordlists[3];
WordList &erlangDoc = *keywordlists[4];
WordList &erlangDocMacro = *keywordlists[5];
int radix_digits = 0;
int exponent_digits = 0;
atom_parse_state_t parse_state = STATE_NULL;
atom_parse_state_t old_parse_state = STATE_NULL;
bool to_late_to_comment = false;
char cur[100];
int old_style = SCE_ERLANG_DEFAULT;
styler.StartAt(startPos);
for (; sc.More(); sc.Forward()) {
int style = SCE_ERLANG_DEFAULT;
if (STATE_NULL != parse_state) {
switch (parse_state) {
case STATE_NULL : sc.SetState(SCE_ERLANG_DEFAULT); break;
/* COMMENTS ------------------------------------------------------*/
case COMMENT : {
if (sc.ch != '%') {
to_late_to_comment = true;
} else if (!to_late_to_comment && sc.ch == '%') {
// Switch to comment level 2 (Function)
sc.ChangeState(SCE_ERLANG_COMMENT_FUNCTION);
old_style = SCE_ERLANG_COMMENT_FUNCTION;
parse_state = COMMENT_FUNCTION;
sc.Forward();
}
}
// V--- Falling through!
// Falls through.
case COMMENT_FUNCTION : {
if (sc.ch != '%') {
to_late_to_comment = true;
} else if (!to_late_to_comment && sc.ch == '%') {
// Switch to comment level 3 (Module)
sc.ChangeState(SCE_ERLANG_COMMENT_MODULE);
old_style = SCE_ERLANG_COMMENT_MODULE;
parse_state = COMMENT_MODULE;
sc.Forward();
}
}
// V--- Falling through!
// Falls through.
case COMMENT_MODULE : {
if (parse_state != COMMENT) {
// Search for comment documentation
if (sc.chNext == '@') {
old_parse_state = parse_state;
parse_state = ('{' == sc.ch)
? COMMENT_DOC_MACRO
: COMMENT_DOC;
sc.ForwardSetState(sc.state);
}
}
// All comments types fall here.
if (sc.MatchLineEnd()) {
to_late_to_comment = false;
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
case COMMENT_DOC :
// V--- Falling through!
case COMMENT_DOC_MACRO : {
if (!isalnum(sc.ch)) {
// Try to match documentation comment
sc.GetCurrent(cur, sizeof(cur));
if (parse_state == COMMENT_DOC_MACRO
&& erlangDocMacro.InList(cur)) {
sc.ChangeState(SCE_ERLANG_COMMENT_DOC_MACRO);
while (sc.ch != '}' && !sc.atLineEnd)
sc.Forward();
} else if (erlangDoc.InList(cur)) {
sc.ChangeState(SCE_ERLANG_COMMENT_DOC);
} else {
sc.ChangeState(old_style);
}
// Switch back to old state
sc.SetState(old_style);
parse_state = old_parse_state;
}
if (sc.MatchLineEnd()) {
to_late_to_comment = false;
sc.ChangeState(old_style);
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
/* -------------------------------------------------------------- */
/* Atoms ---------------------------------------------------------*/
case ATOM_UNQUOTED : {
if ('@' == sc.ch){
parse_state = NODE_NAME_UNQUOTED;
} else if (sc.ch == ':') {
// Searching for module name
if (sc.chNext == ' ') {
// error
sc.ChangeState(SCE_ERLANG_UNKNOWN);
parse_state = STATE_NULL;
} else {
sc.Forward();
if (isalnum(sc.ch) || (sc.ch == '\'')) {
sc.GetCurrent(cur, sizeof(cur));
sc.ChangeState(SCE_ERLANG_MODULES);
sc.SetState(SCE_ERLANG_MODULES);
}
if (sc.ch == '\'') {
parse_state = ATOM_QUOTED;
}
}
} else if (!IsAWordChar(sc.ch)) {
sc.GetCurrent(cur, sizeof(cur));
if (reservedWords.InList(cur)) {
style = SCE_ERLANG_KEYWORD;
} else if (erlangBIFs.InList(cur)
&& strcmp(cur,"erlang:")){
style = SCE_ERLANG_BIFS;
} else if (sc.ch == '(' || '/' == sc.ch){
style = SCE_ERLANG_FUNCTION_NAME;
} else {
style = SCE_ERLANG_ATOM;
}
sc.ChangeState(style);
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
case ATOM_QUOTED : {
if ( '@' == sc.ch ){
parse_state = NODE_NAME_QUOTED;
} else if ('\'' == sc.ch && '\\' != sc.chPrev) {
sc.ChangeState(SCE_ERLANG_ATOM_QUOTED);
sc.ForwardSetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
/* -------------------------------------------------------------- */
/* Node names ----------------------------------------------------*/
case NODE_NAME_UNQUOTED : {
if ('@' == sc.ch) {
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
} else if (!IsAWordChar(sc.ch)) {
sc.ChangeState(SCE_ERLANG_NODE_NAME);
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
case NODE_NAME_QUOTED : {
if ('@' == sc.ch) {
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
} else if ('\'' == sc.ch && '\\' != sc.chPrev) {
sc.ChangeState(SCE_ERLANG_NODE_NAME_QUOTED);
sc.ForwardSetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
/* -------------------------------------------------------------- */
/* Records -------------------------------------------------------*/
case RECORD_START : {
if ('\'' == sc.ch) {
parse_state = RECORD_QUOTED;
} else if (isalpha(sc.ch) && islower(sc.ch)) {
parse_state = RECORD_UNQUOTED;
} else { // error
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
case RECORD_UNQUOTED : {
if (!IsAWordChar(sc.ch)) {
sc.ChangeState(SCE_ERLANG_RECORD);
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
case RECORD_QUOTED : {
if ('\'' == sc.ch && '\\' != sc.chPrev) {
sc.ChangeState(SCE_ERLANG_RECORD_QUOTED);
sc.ForwardSetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
/* -------------------------------------------------------------- */
/* Macros --------------------------------------------------------*/
case MACRO_START : {
if ('\'' == sc.ch) {
parse_state = MACRO_QUOTED;
} else if (isalpha(sc.ch)) {
parse_state = MACRO_UNQUOTED;
} else { // error
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
case MACRO_UNQUOTED : {
if (!IsAWordChar(sc.ch)) {
sc.ChangeState(SCE_ERLANG_MACRO);
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
case MACRO_QUOTED : {
if ('\'' == sc.ch && '\\' != sc.chPrev) {
sc.ChangeState(SCE_ERLANG_MACRO_QUOTED);
sc.ForwardSetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
/* -------------------------------------------------------------- */
/* Numerics ------------------------------------------------------*/
/* Simple integer */
case NUMERAL_START : {
if (isdigit(sc.ch)) {
radix_digits *= 10;
radix_digits += sc.ch - '0'; // Assuming ASCII here!
} else if ('#' == sc.ch) {
if (2 > radix_digits || 36 < radix_digits) {
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
} else {
parse_state = NUMERAL_BASE_VALUE;
}
} else if ('.' == sc.ch && isdigit(sc.chNext)) {
radix_digits = 0;
parse_state = NUMERAL_FLOAT;
} else if ('e' == sc.ch || 'E' == sc.ch) {
exponent_digits = 0;
parse_state = NUMERAL_EXPONENT;
} else {
radix_digits = 0;
sc.ChangeState(SCE_ERLANG_NUMBER);
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
/* Integer in other base than 10 (x#yyy) */
case NUMERAL_BASE_VALUE : {
if (!is_radix(radix_digits,sc.ch)) {
radix_digits = 0;
if (!isalnum(sc.ch))
sc.ChangeState(SCE_ERLANG_NUMBER);
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
/* Float (x.yyy) */
case NUMERAL_FLOAT : {
if ('e' == sc.ch || 'E' == sc.ch) {
exponent_digits = 0;
parse_state = NUMERAL_EXPONENT;
} else if (!isdigit(sc.ch)) {
sc.ChangeState(SCE_ERLANG_NUMBER);
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
/* Exponent, either integer or float (xEyy, x.yyEzzz) */
case NUMERAL_EXPONENT : {
if (('-' == sc.ch || '+' == sc.ch)
&& (isdigit(sc.chNext))) {
sc.Forward();
} else if (!isdigit(sc.ch)) {
if (0 < exponent_digits)
sc.ChangeState(SCE_ERLANG_NUMBER);
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
} else {
++exponent_digits;
}
} break;
/* -------------------------------------------------------------- */
/* Preprocessor --------------------------------------------------*/
case PREPROCESSOR : {
if (!IsAWordChar(sc.ch)) {
sc.GetCurrent(cur, sizeof(cur));
if (erlangPreproc.InList(cur)) {
style = SCE_ERLANG_PREPROC;
} else if (erlangModulesAtt.InList(cur)) {
style = SCE_ERLANG_MODULES_ATT;
}
sc.ChangeState(style);
sc.SetState(SCE_ERLANG_DEFAULT);
parse_state = STATE_NULL;
}
} break;
}
} /* End of : STATE_NULL != parse_state */
else
{
switch (sc.state) {
case SCE_ERLANG_VARIABLE : {
if (!IsAWordChar(sc.ch))
sc.SetState(SCE_ERLANG_DEFAULT);
} break;
case SCE_ERLANG_STRING : {
if (sc.ch == '\"' && sc.chPrev != '\\')
sc.ForwardSetState(SCE_ERLANG_DEFAULT);
} break;
case SCE_ERLANG_COMMENT : {
if (sc.atLineEnd)
sc.SetState(SCE_ERLANG_DEFAULT);
} break;
case SCE_ERLANG_CHARACTER : {
if (sc.chPrev == '\\') {
sc.ForwardSetState(SCE_ERLANG_DEFAULT);
} else if (sc.ch != '\\') {
sc.ForwardSetState(SCE_ERLANG_DEFAULT);
}
} break;
case SCE_ERLANG_OPERATOR : {
if (sc.chPrev == '.') {
if (sc.ch == '*' || sc.ch == '/' || sc.ch == '\\'
|| sc.ch == '^') {
sc.ForwardSetState(SCE_ERLANG_DEFAULT);
} else if (sc.ch == '\'') {
sc.ForwardSetState(SCE_ERLANG_DEFAULT);
} else {
sc.SetState(SCE_ERLANG_DEFAULT);
}
} else {
sc.SetState(SCE_ERLANG_DEFAULT);
}
} break;
}
}
if (sc.state == SCE_ERLANG_DEFAULT) {
bool no_new_state = false;
switch (sc.ch) {
case '\"' : sc.SetState(SCE_ERLANG_STRING); break;
case '$' : sc.SetState(SCE_ERLANG_CHARACTER); break;
case '%' : {
parse_state = COMMENT;
sc.SetState(SCE_ERLANG_COMMENT);
} break;
case '#' : {
parse_state = RECORD_START;
sc.SetState(SCE_ERLANG_UNKNOWN);
} break;
case '?' : {
parse_state = MACRO_START;
sc.SetState(SCE_ERLANG_UNKNOWN);
} break;
case '\'' : {
parse_state = ATOM_QUOTED;
sc.SetState(SCE_ERLANG_UNKNOWN);
} break;
case '+' :
case '-' : {
if (IsADigit(sc.chNext)) {
parse_state = NUMERAL_START;
radix_digits = 0;
sc.SetState(SCE_ERLANG_UNKNOWN);
} else if (sc.ch != '+') {
parse_state = PREPROCESSOR;
sc.SetState(SCE_ERLANG_UNKNOWN);
}
} break;
default : no_new_state = true;
}
if (no_new_state) {
if (isdigit(sc.ch)) {
parse_state = NUMERAL_START;
radix_digits = sc.ch - '0';
sc.SetState(SCE_ERLANG_UNKNOWN);
} else if (isupper(sc.ch) || '_' == sc.ch) {
sc.SetState(SCE_ERLANG_VARIABLE);
} else if (isalpha(sc.ch)) {
parse_state = ATOM_UNQUOTED;
sc.SetState(SCE_ERLANG_UNKNOWN);
} else if (isoperator(static_cast<char>(sc.ch))
|| sc.ch == '\\') {
sc.SetState(SCE_ERLANG_OPERATOR);
}
}
}
}
sc.Complete();
}
static int ClassifyErlangFoldPoint(
Accessor &styler,
int styleNext,
Sci_Position keyword_start
) {
int lev = 0;
if (styler.Match(keyword_start,"case")
|| (
styler.Match(keyword_start,"fun")
&& (SCE_ERLANG_FUNCTION_NAME != styleNext)
)
|| styler.Match(keyword_start,"if")
|| styler.Match(keyword_start,"query")
|| styler.Match(keyword_start,"receive")
) {
++lev;
} else if (styler.Match(keyword_start,"end")) {
--lev;
}
return lev;
}
static void FoldErlangDoc(
Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList** /*keywordlists*/, Accessor &styler
) {
Sci_PositionU endPos = startPos + length;
Sci_Position currentLine = styler.GetLine(startPos);
int lev;
int previousLevel = styler.LevelAt(currentLine) & SC_FOLDLEVELNUMBERMASK;
int currentLevel = previousLevel;
int styleNext = styler.StyleAt(startPos);
int style = initStyle;
int stylePrev;
Sci_Position keyword_start = 0;
char ch;
char chNext = styler.SafeGetCharAt(startPos);
bool atEOL;
for (Sci_PositionU i = startPos; i < endPos; i++) {
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
// Get styles
stylePrev = style;
style = styleNext;
styleNext = styler.StyleAt(i + 1);
atEOL = ((ch == '\r') && (chNext != '\n')) || (ch == '\n');
if (stylePrev != SCE_ERLANG_KEYWORD
&& style == SCE_ERLANG_KEYWORD) {
keyword_start = i;
}
// Fold on keywords
if (stylePrev == SCE_ERLANG_KEYWORD
&& style != SCE_ERLANG_KEYWORD
&& style != SCE_ERLANG_ATOM
) {
currentLevel += ClassifyErlangFoldPoint(styler,
styleNext,
keyword_start);
}
// Fold on comments
if (style == SCE_ERLANG_COMMENT
|| style == SCE_ERLANG_COMMENT_MODULE
|| style == SCE_ERLANG_COMMENT_FUNCTION) {
if (ch == '%' && chNext == '{') {
currentLevel++;
} else if (ch == '%' && chNext == '}') {
currentLevel--;
}
}
// Fold on braces
if (style == SCE_ERLANG_OPERATOR) {
if (ch == '{' || ch == '(' || ch == '[') {
currentLevel++;
} else if (ch == '}' || ch == ')' || ch == ']') {
currentLevel--;
}
}
if (atEOL) {
lev = previousLevel;
if (currentLevel > previousLevel)
lev |= SC_FOLDLEVELHEADERFLAG;
if (lev != styler.LevelAt(currentLine))
styler.SetLevel(currentLine, lev);
currentLine++;
previousLevel = currentLevel;
}
}
// Fill in the real level of the next line, keeping the current flags as they will be filled in later
styler.SetLevel(currentLine,
previousLevel
| (styler.LevelAt(currentLine) & ~SC_FOLDLEVELNUMBERMASK));
}
static const char * const erlangWordListDesc[] = {
"Erlang Reserved words",
"Erlang BIFs",
"Erlang Preprocessor",
"Erlang Module Attributes",
"Erlang Documentation",
"Erlang Documentation Macro",
0
};
LexerModule lmErlang(
SCLEX_ERLANG,
ColouriseErlangDoc,
"erlang",
FoldErlangDoc,
erlangWordListDesc);

View File

@ -0,0 +1,431 @@
// Scintilla source code edit control
/** @file LexErrorList.cxx
** Lexer for error lists. Used for the output pane in SciTE.
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cstdio>
#include <cstdarg>
#include <string>
#include <string_view>
#include <initializer_list>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "InList.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
using namespace Lexilla;
namespace {
bool strstart(const char *haystack, const char *needle) noexcept {
return strncmp(haystack, needle, strlen(needle)) == 0;
}
constexpr bool Is0To9(char ch) noexcept {
return (ch >= '0') && (ch <= '9');
}
constexpr bool Is1To9(char ch) noexcept {
return (ch >= '1') && (ch <= '9');
}
bool AtEOL(Accessor &styler, Sci_Position i) {
return (styler[i] == '\n') ||
((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n'));
}
bool IsGccExcerpt(const char *s) noexcept {
while (*s) {
if (s[0] == ' ' && s[1] == '|' && (s[2] == ' ' || s[2] == '+')) {
return true;
}
if (!(s[0] == ' ' || s[0] == '+' || Is0To9(s[0]))) {
return false;
}
s++;
}
return true;
}
const std::string_view bashDiagnosticMark = ": line ";
bool IsBashDiagnostic(std::string_view sv) {
const size_t mark = sv.find(bashDiagnosticMark);
if (mark == std::string_view::npos) {
return false;
}
std::string_view rest = sv.substr(mark + bashDiagnosticMark.length());
if (rest.empty() || !Is0To9(rest.front())) {
return false;
}
while (!rest.empty() && Is0To9(rest.front())) {
rest.remove_prefix(1);
}
return !rest.empty() && (rest.front() == ':');
}
int RecogniseErrorListLine(const char *lineBuffer, Sci_PositionU lengthLine, Sci_Position &startValue) {
if (lineBuffer[0] == '>') {
// Command or return status
return SCE_ERR_CMD;
} else if (lineBuffer[0] == '<') {
// Diff removal.
return SCE_ERR_DIFF_DELETION;
} else if (lineBuffer[0] == '!') {
return SCE_ERR_DIFF_CHANGED;
} else if (lineBuffer[0] == '+') {
if (strstart(lineBuffer, "+++ ")) {
return SCE_ERR_DIFF_MESSAGE;
} else {
return SCE_ERR_DIFF_ADDITION;
}
} else if (lineBuffer[0] == '-') {
if (strstart(lineBuffer, "--- ")) {
return SCE_ERR_DIFF_MESSAGE;
} else {
return SCE_ERR_DIFF_DELETION;
}
} else if (strstart(lineBuffer, "cf90-")) {
// Absoft Pro Fortran 90/95 v8.2 error and/or warning message
return SCE_ERR_ABSF;
} else if (strstart(lineBuffer, "fortcom:")) {
// Intel Fortran Compiler v8.0 error/warning message
return SCE_ERR_IFORT;
} else if (strstr(lineBuffer, "File \"") && strstr(lineBuffer, ", line ")) {
return SCE_ERR_PYTHON;
} else if (strstr(lineBuffer, " in ") && strstr(lineBuffer, " on line ")) {
return SCE_ERR_PHP;
} else if ((strstart(lineBuffer, "Error ") ||
strstart(lineBuffer, "Warning ")) &&
strstr(lineBuffer, " at (") &&
strstr(lineBuffer, ") : ") &&
(strstr(lineBuffer, " at (") < strstr(lineBuffer, ") : "))) {
// Intel Fortran Compiler error/warning message
return SCE_ERR_IFC;
} else if (strstart(lineBuffer, "Error ")) {
// Borland error message
return SCE_ERR_BORLAND;
} else if (strstart(lineBuffer, "Warning ")) {
// Borland warning message
return SCE_ERR_BORLAND;
} else if (strstr(lineBuffer, "at line ") &&
(strstr(lineBuffer, "at line ") < (lineBuffer + lengthLine)) &&
strstr(lineBuffer, "file ") &&
(strstr(lineBuffer, "file ") < (lineBuffer + lengthLine))) {
// Lua 4 error message
return SCE_ERR_LUA;
} else if (strstr(lineBuffer, " at ") &&
(strstr(lineBuffer, " at ") < (lineBuffer + lengthLine)) &&
strstr(lineBuffer, " line ") &&
(strstr(lineBuffer, " line ") < (lineBuffer + lengthLine)) &&
(strstr(lineBuffer, " at ") + 4 < (strstr(lineBuffer, " line ")))) {
// perl error message:
// <message> at <file> line <line>
return SCE_ERR_PERL;
} else if ((lengthLine >= 6) &&
(memcmp(lineBuffer, " at ", 6) == 0) &&
strstr(lineBuffer, ":line ")) {
// A .NET traceback
return SCE_ERR_NET;
} else if (strstart(lineBuffer, "Line ") &&
strstr(lineBuffer, ", file ")) {
// Essential Lahey Fortran error message
return SCE_ERR_ELF;
} else if (strstart(lineBuffer, "line ") &&
strstr(lineBuffer, " column ")) {
// HTML tidy style: line 42 column 1
return SCE_ERR_TIDY;
} else if (strstart(lineBuffer, "\tat ") &&
strchr(lineBuffer, '(') &&
strstr(lineBuffer, ".java:")) {
// Java stack back trace
return SCE_ERR_JAVA_STACK;
} else if (strstart(lineBuffer, "In file included from ") ||
strstart(lineBuffer, " from ")) {
// GCC showing include path to following error
return SCE_ERR_GCC_INCLUDED_FROM;
} else if (strstart(lineBuffer, "NMAKE : fatal error")) {
// Microsoft nmake fatal error:
// NMAKE : fatal error <code>: <program> : return code <return>
return SCE_ERR_MS;
} else if (strstr(lineBuffer, "warning LNK") ||
strstr(lineBuffer, "error LNK")) {
// Microsoft linker warning:
// {<object> : } (warning|error) LNK9999
return SCE_ERR_MS;
} else if (IsBashDiagnostic(lineBuffer)) {
// Bash diagnostic
// <filename>: line <line>:<message>
return SCE_ERR_BASH;
} else if (IsGccExcerpt(lineBuffer)) {
// GCC code excerpt and pointer to issue
// 73 | GTimeVal last_popdown;
// | ^~~~~~~~~~~~
return SCE_ERR_GCC_EXCERPT;
} else {
// Look for one of the following formats:
// GCC: <filename>:<line>:<message>
// Microsoft: <filename>(<line>) :<message>
// Common: <filename>(<line>): warning|error|note|remark|catastrophic|fatal
// Common: <filename>(<line>) warning|error|note|remark|catastrophic|fatal
// Microsoft: <filename>(<line>,<column>)<message>
// CTags: <identifier>\t<filename>\t<message>
// Lua 5 traceback: \t<filename>:<line>:<message>
// Lua 5.1: <exe>: <filename>:<line>:<message>
const bool initialTab = (lineBuffer[0] == '\t');
bool initialColonPart = false;
bool canBeCtags = !initialTab; // For ctags must have an identifier with no spaces then a tab
enum { stInitial,
stGccStart, stGccDigit, stGccColumn, stGcc,
stMsStart, stMsDigit, stMsBracket, stMsVc, stMsDigitComma, stMsDotNet,
stCtagsStart, stCtagsFile, stCtagsStartString, stCtagsStringDollar, stCtags,
stUnrecognized
} state = stInitial;
for (Sci_PositionU i = 0; i < lengthLine; i++) {
const char ch = lineBuffer[i];
char chNext = ' ';
if ((i + 1) < lengthLine)
chNext = lineBuffer[i + 1];
if (state == stInitial) {
if (ch == ':') {
// May be GCC, or might be Lua 5 (Lua traceback same but with tab prefix)
if ((chNext != '\\') && (chNext != '/') && (chNext != ' ')) {
// This check is not completely accurate as may be on
// GTK+ with a file name that includes ':'.
state = stGccStart;
} else if (chNext == ' ') { // indicates a Lua 5.1 error message
initialColonPart = true;
}
} else if ((ch == '(') && Is1To9(chNext) && (!initialTab)) {
// May be Microsoft
// Check against '0' often removes phone numbers
state = stMsStart;
} else if ((ch == '\t') && canBeCtags) {
// May be CTags
state = stCtagsStart;
} else if (ch == ' ') {
canBeCtags = false;
}
} else if (state == stGccStart) { // <filename>:
state = ((ch == '-') || Is0To9(ch)) ? stGccDigit : stUnrecognized;
} else if (state == stGccDigit) { // <filename>:<line>
if (ch == ':') {
state = stGccColumn; // :9.*: is GCC
startValue = i + 1;
} else if (!Is0To9(ch)) {
state = stUnrecognized;
}
} else if (state == stGccColumn) { // <filename>:<line>:<column>
if (!Is0To9(ch)) {
state = stGcc;
if (ch == ':')
startValue = i + 1;
break;
}
} else if (state == stMsStart) { // <filename>(
state = Is0To9(ch) ? stMsDigit : stUnrecognized;
} else if (state == stMsDigit) { // <filename>(<line>
if (ch == ',') {
state = stMsDigitComma;
} else if (ch == ')') {
state = stMsBracket;
} else if ((ch != ' ') && !Is0To9(ch)) {
state = stUnrecognized;
}
} else if (state == stMsBracket) { // <filename>(<line>)
if ((ch == ' ') && (chNext == ':')) {
state = stMsVc;
} else if ((ch == ':' && chNext == ' ') || (ch == ' ')) {
// Possibly Delphi.. don't test against chNext as it's one of the strings below.
char word[512];
unsigned numstep = 0;
if (ch == ' ')
numstep = 1; // ch was ' ', handle as if it's a delphi errorline, only add 1 to i.
else
numstep = 2; // otherwise add 2.
Sci_PositionU chPos = 0;
for (Sci_PositionU j = i + numstep; j < lengthLine && IsUpperOrLowerCase(lineBuffer[j]) && chPos < sizeof(word) - 1; j++)
word[chPos++] = lineBuffer[j];
word[chPos] = 0;
if (InListCaseInsensitive(word, {"error", "warning", "fatal", "catastrophic", "note", "remark"})) {
state = stMsVc;
} else {
state = stUnrecognized;
}
} else {
state = stUnrecognized;
}
} else if (state == stMsDigitComma) { // <filename>(<line>,
if (ch == ')') {
state = stMsDotNet;
break;
} else if ((ch != ' ') && !Is0To9(ch)) {
state = stUnrecognized;
}
} else if (state == stCtagsStart) {
if (ch == '\t') {
state = stCtagsFile;
}
} else if (state == stCtagsFile) {
if ((lineBuffer[i - 1] == '\t') &&
((ch == '/' && chNext == '^') || Is0To9(ch))) {
state = stCtags;
break;
} else if ((ch == '/') && (chNext == '^')) {
state = stCtagsStartString;
}
} else if ((state == stCtagsStartString) && ((lineBuffer[i] == '$') && (lineBuffer[i + 1] == '/'))) {
state = stCtagsStringDollar;
break;
}
}
if (state == stGcc) {
return initialColonPart ? SCE_ERR_LUA : SCE_ERR_GCC;
} else if ((state == stMsVc) || (state == stMsDotNet)) {
return SCE_ERR_MS;
} else if ((state == stCtagsStringDollar) || (state == stCtags)) {
return SCE_ERR_CTAG;
} else if (initialColonPart && strstr(lineBuffer, ": warning C")) {
// Microsoft warning without line number
// <filename>: warning C9999
return SCE_ERR_MS;
} else {
return SCE_ERR_DEFAULT;
}
}
}
#define CSI "\033["
constexpr bool SequenceEnd(int ch) noexcept {
return (ch == 0) || ((ch >= '@') && (ch <= '~'));
}
int StyleFromSequence(const char *seq) noexcept {
int bold = 0;
int colour = 0;
while (!SequenceEnd(*seq)) {
if (Is0To9(*seq)) {
int base = *seq - '0';
if (Is0To9(seq[1])) {
base = base * 10;
base += seq[1] - '0';
seq++;
}
if (base == 0) {
colour = 0;
bold = 0;
}
else if (base == 1) {
bold = 1;
}
else if (base >= 30 && base <= 37) {
colour = base - 30;
}
}
seq++;
}
return SCE_ERR_ES_BLACK + bold * 8 + colour;
}
void ColouriseErrorListLine(
const std::string &lineBuffer,
Sci_PositionU endPos,
Accessor &styler,
bool valueSeparate,
bool escapeSequences) {
Sci_Position startValue = -1;
const Sci_PositionU lengthLine = lineBuffer.length();
const int style = RecogniseErrorListLine(lineBuffer.c_str(), lengthLine, startValue);
if (escapeSequences && strstr(lineBuffer.c_str(), CSI)) {
const Sci_Position startPos = endPos - lengthLine;
const char *linePortion = lineBuffer.c_str();
Sci_Position startPortion = startPos;
int portionStyle = style;
while (const char *startSeq = strstr(linePortion, CSI)) {
if (startSeq > linePortion) {
styler.ColourTo(startPortion + (startSeq - linePortion), portionStyle);
}
const char *endSeq = startSeq + 2;
while (!SequenceEnd(*endSeq))
endSeq++;
const Sci_Position endSeqPosition = startPortion + (endSeq - linePortion) + 1;
switch (*endSeq) {
case 0:
styler.ColourTo(endPos, SCE_ERR_ESCSEQ_UNKNOWN);
return;
case 'm': // Colour command
styler.ColourTo(endSeqPosition, SCE_ERR_ESCSEQ);
portionStyle = StyleFromSequence(startSeq+2);
break;
case 'K': // Erase to end of line -> ignore
styler.ColourTo(endSeqPosition, SCE_ERR_ESCSEQ);
break;
default:
styler.ColourTo(endSeqPosition, SCE_ERR_ESCSEQ_UNKNOWN);
portionStyle = style;
}
startPortion = endSeqPosition;
linePortion = endSeq + 1;
}
styler.ColourTo(endPos, portionStyle);
} else {
if (valueSeparate && (startValue >= 0)) {
styler.ColourTo(endPos - (lengthLine - startValue), style);
styler.ColourTo(endPos, SCE_ERR_VALUE);
} else {
styler.ColourTo(endPos, style);
}
}
}
void ColouriseErrorListDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
std::string lineBuffer;
styler.StartAt(startPos);
styler.StartSegment(startPos);
// property lexer.errorlist.value.separate
// For lines in the output pane that are matches from Find in Files or GCC-style
// diagnostics, style the path and line number separately from the rest of the
// line with style 21 used for the rest of the line.
// This allows matched text to be more easily distinguished from its location.
const bool valueSeparate = styler.GetPropertyInt("lexer.errorlist.value.separate", 0) != 0;
// property lexer.errorlist.escape.sequences
// Set to 1 to interpret escape sequences.
const bool escapeSequences = styler.GetPropertyInt("lexer.errorlist.escape.sequences") != 0;
for (Sci_PositionU i = startPos; i < startPos + length; i++) {
lineBuffer.push_back(styler[i]);
if (AtEOL(styler, i)) {
// End of line met, colourise it
ColouriseErrorListLine(lineBuffer, i, styler, valueSeparate, escapeSequences);
lineBuffer.clear();
}
}
if (!lineBuffer.empty()) { // Last line does not have ending characters
ColouriseErrorListLine(lineBuffer, startPos + length - 1, styler, valueSeparate, escapeSequences);
}
}
const char *const emptyWordListDesc[] = {
nullptr
};
}
LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist", nullptr, emptyWordListDesc);

View File

@ -0,0 +1,769 @@
/**
* @file LexFSharp.cxx
* Lexer for F# 5.0
* Copyright (c) 2021 Robert Di Pardo <dipardo.r@gmail.com>
* Parts of LexerFSharp::Lex were adapted from LexCaml.cxx by Robert Roessler ("RR").
* Parts of LexerFSharp::Fold were adapted from LexCPP.cxx by Neil Hodgson and Udo Lechner.
* The License.txt file describes the conditions under which this software may be distributed.
*/
// clang-format off
#include <cstdlib>
#include <cassert>
#include <string>
#include <string_view>
#include <map>
#include <functional>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "DefaultLexer.h"
// clang-format on
using namespace Scintilla;
using namespace Lexilla;
static const char *const lexerName = "fsharp";
static constexpr int WORDLIST_SIZE = 5;
static const char *const fsharpWordLists[] = {
"standard language keywords",
"core functions, including those in the FSharp.Collections namespace",
"built-in types, core namespaces, modules",
"optional",
"optional",
nullptr,
};
static constexpr int keywordClasses[] = {
SCE_FSHARP_KEYWORD, SCE_FSHARP_KEYWORD2, SCE_FSHARP_KEYWORD3, SCE_FSHARP_KEYWORD4, SCE_FSHARP_KEYWORD5,
};
namespace {
struct OptionsFSharp {
bool fold = true;
bool foldCompact = true;
bool foldComment = true;
bool foldCommentStream = true;
bool foldCommentMultiLine = true;
bool foldPreprocessor = false;
bool foldImports = true;
};
struct OptionSetFSharp : public OptionSet<OptionsFSharp> {
OptionSetFSharp() {
DefineProperty("fold", &OptionsFSharp::fold);
DefineProperty("fold.compact", &OptionsFSharp::foldCompact);
DefineProperty("fold.comment", &OptionsFSharp::foldComment,
"Setting this option to 0 disables comment folding in F# files.");
DefineProperty("fold.fsharp.comment.stream", &OptionsFSharp::foldCommentStream,
"Setting this option to 0 disables folding of ML-style comments in F# files when "
"fold.comment=1.");
DefineProperty("fold.fsharp.comment.multiline", &OptionsFSharp::foldCommentMultiLine,
"Setting this option to 0 disables folding of grouped line comments in F# files when "
"fold.comment=1.");
DefineProperty("fold.fsharp.preprocessor", &OptionsFSharp::foldPreprocessor,
"Setting this option to 1 enables folding of F# compiler directives.");
DefineProperty("fold.fsharp.imports", &OptionsFSharp::foldImports,
"Setting this option to 0 disables folding of F# import declarations.");
DefineWordListSets(fsharpWordLists);
}
};
struct FSharpString {
Sci_Position startPos = INVALID_POSITION;
int startChar = '"', nextChar = '\0';
constexpr bool HasLength() const {
return startPos > INVALID_POSITION;
}
constexpr bool CanInterpolate() const {
return startChar == '$' || (startChar == '@' && nextChar == '$');
}
constexpr bool IsVerbatim() const {
return startChar == '@' || (startChar == '$' && nextChar == '@');
}
};
class UnicodeChar {
enum class Notation { none, asciiDec, asciiHex, utf16, utf32 };
Notation type = Notation::none;
// single-byte Unicode char (000 - 255)
int asciiDigits[3] = { 0 };
int maxDigit = '9';
int toEnd = 0;
bool invalid = false;
public:
UnicodeChar() noexcept = default;
explicit UnicodeChar(const int prefix) {
if (IsADigit(prefix)) {
*asciiDigits = prefix;
if (*asciiDigits >= '0' && *asciiDigits <= '2') {
type = Notation::asciiDec;
// count first digit as "prefix"
toEnd = 2;
}
} else if (prefix == 'x' || prefix == 'u' || prefix == 'U') {
switch (prefix) {
case 'x':
type = Notation::asciiHex;
toEnd = 2;
break;
case 'u':
type = Notation::utf16;
toEnd = 4;
break;
case 'U':
type = Notation::utf32;
toEnd = 8;
break;
}
}
}
void Parse(const int ch) {
invalid = false;
switch (type) {
case Notation::asciiDec: {
maxDigit = (*asciiDigits < '2') ? '9' : (asciiDigits[1] <= '4') ? '9' : '5';
if (IsADigit(ch) && asciiDigits[1] <= maxDigit && ch <= maxDigit) {
asciiDigits[1] = ch;
toEnd--;
} else {
invalid = true;
}
break;
}
case Notation::asciiHex:
case Notation::utf16:
if (IsADigit(ch, 16)) {
toEnd--;
} else {
invalid = true;
}
break;
case Notation::utf32:
if ((toEnd > 6 && ch == '0') || (toEnd <= 6 && IsADigit(ch, 16))) {
toEnd--;
} else {
invalid = true;
}
break;
case Notation::none:
break;
}
}
constexpr bool AtEnd() noexcept {
return invalid || type == Notation::none || (type != Notation::none && toEnd < 0);
}
};
inline bool MatchStreamCommentStart(StyleContext &cxt) {
// match (* ... *), but allow point-free usage of the `*` operator,
// e.g. List.fold (*) 1 [ 1; 2; 3 ]
return (cxt.Match('(', '*') && cxt.GetRelative(2) != ')');
}
inline bool MatchStreamCommentEnd(const StyleContext &cxt) {
return (cxt.ch == ')' && cxt.chPrev == '*');
}
inline bool MatchLineComment(const StyleContext &cxt) {
// style shebang lines as comments in F# scripts:
// https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf#page=30&zoom=auto,-98,537
return cxt.Match('/', '/') || cxt.Match('#', '!');
}
inline bool MatchLineNumberStart(StyleContext &cxt) {
return cxt.atLineStart && (cxt.MatchIgnoreCase("#line") ||
(cxt.ch == '#' && (IsADigit(cxt.chNext) || IsADigit(cxt.GetRelative(2)))));
}
inline bool MatchPPDirectiveStart(const StyleContext &cxt) {
return (cxt.atLineStart && cxt.ch == '#' && iswordstart(cxt.chNext));
}
inline bool MatchTypeAttributeStart(const StyleContext &cxt) {
return cxt.Match('[', '<');
}
inline bool MatchTypeAttributeEnd(const StyleContext &cxt) {
return (cxt.ch == ']' && cxt.chPrev == '>');
}
inline bool MatchQuotedExpressionStart(const StyleContext &cxt) {
return cxt.Match('<', '@');
}
inline bool MatchQuotedExpressionEnd(const StyleContext &cxt) {
return (cxt.ch == '>' && cxt.chPrev == '@');
}
inline bool MatchStringStart(StyleContext &cxt) {
return (cxt.ch == '"' || cxt.Match("@\"") || cxt.Match("$\"") || cxt.Match("@$\"") || cxt.Match("$@\"") ||
cxt.Match("``"));
}
inline bool FollowsEscapedBackslash(StyleContext &cxt) {
int count = 0;
for (Sci_Position offset = 1; cxt.GetRelative(-offset) == '\\'; offset++)
count++;
return count % 2 != 0;
}
inline bool MatchStringEnd(StyleContext &cxt, const FSharpString &fsStr) {
return (fsStr.HasLength() &&
// end of quoted identifier?
((cxt.ch == '`' && cxt.chPrev == '`') ||
// end of literal or interpolated triple-quoted string?
((fsStr.startChar == '"' || (fsStr.CanInterpolate() && !(fsStr.IsVerbatim() || cxt.chPrev == '$'))) &&
cxt.MatchIgnoreCase("\"\"\"")) ||
// end of verbatim string?
(fsStr.IsVerbatim() &&
// embedded quotes must be in pairs
cxt.ch == '"' && cxt.chNext != '"' &&
(cxt.chPrev != '"' ||
// empty verbatim string?
((cxt.GetRelative(-2) == '@' || cxt.GetRelative(-2) == '$') ||
// pair of quotes at end of string?
(cxt.GetRelative(-2) == '"' && !(cxt.GetRelative(-3) == '@' || cxt.GetRelative(-3) == '$'))))))) ||
(!fsStr.HasLength() && cxt.ch == '"' &&
((cxt.chPrev != '\\' || (cxt.GetRelative(-2) == '\\' && !FollowsEscapedBackslash(cxt))) ||
// treat backslashes as char literals in verbatim strings
(fsStr.IsVerbatim() && cxt.chPrev == '\\')));
}
inline bool MatchCharacterStart(StyleContext &cxt) {
// don't style generic type parameters: 'a, 'b, 'T, etc.
return (cxt.ch == '\'' && !(cxt.chPrev == ':' || cxt.GetRelative(-2) == ':'));
}
inline bool CanEmbedQuotes(StyleContext &cxt) {
// allow unescaped double quotes inside literal or interpolated triple-quoted strings, verbatim strings,
// and quoted identifiers:
// - https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/strings
// - https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/interpolated-strings#syntax
// - https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf#page=25&zoom=auto,-98,600
return cxt.Match("$\"\"\"") || cxt.Match("\"\"\"") || cxt.Match("@$\"\"\"") || cxt.Match("$@\"\"\"") ||
cxt.Match('@', '"') || cxt.Match('`', '`');
}
inline bool IsLineEnd(StyleContext &cxt, const Sci_Position offset) {
const int ch = cxt.GetRelative(offset, '\n');
return (ch == '\r' || ch == '\n');
}
class LexerFSharp : public DefaultLexer {
WordList keywords[WORDLIST_SIZE];
OptionsFSharp options;
OptionSetFSharp optionSet;
CharacterSet setOperators;
CharacterSet setFormatSpecs;
CharacterSet setDotNetFormatSpecs;
CharacterSet setFormatFlags;
CharacterSet numericMetaChars1;
CharacterSet numericMetaChars2;
std::map<int, int> numericPrefixes = { { 'b', 2 }, { 'o', 8 }, { 'x', 16 } };
public:
explicit LexerFSharp()
: DefaultLexer(lexerName, SCLEX_FSHARP),
setOperators(CharacterSet::setNone, "~^'-+*/%=@|&<>()[]{};,:!?"),
setFormatSpecs(CharacterSet::setNone, ".%aAbBcdeEfFgGiMoOstuxX0123456789"),
setDotNetFormatSpecs(CharacterSet::setNone, "cCdDeEfFgGnNpPxX"),
setFormatFlags(CharacterSet::setNone, ".-+0 "),
numericMetaChars1(CharacterSet::setNone, "_uU"),
numericMetaChars2(CharacterSet::setNone, "fFIlLmMnsy") {
}
LexerFSharp(const LexerFSharp &) = delete;
LexerFSharp(LexerFSharp &&) = delete;
LexerFSharp &operator=(const LexerFSharp &) = delete;
LexerFSharp &operator=(LexerFSharp &&) = delete;
static ILexer5 *LexerFactoryFSharp() {
return new LexerFSharp();
}
virtual ~LexerFSharp() {
}
void SCI_METHOD Release() noexcept override {
delete this;
}
int SCI_METHOD Version() const noexcept override {
return lvRelease5;
}
const char *SCI_METHOD GetName() noexcept override {
return lexerName;
}
int SCI_METHOD GetIdentifier() noexcept override {
return SCLEX_FSHARP;
}
int SCI_METHOD LineEndTypesSupported() noexcept override {
return SC_LINE_END_TYPE_DEFAULT;
}
void *SCI_METHOD PrivateCall(int, void *) noexcept override {
return nullptr;
}
const char *SCI_METHOD DescribeWordListSets() override {
return optionSet.DescribeWordListSets();
}
const char *SCI_METHOD PropertyNames() override {
return optionSet.PropertyNames();
}
int SCI_METHOD PropertyType(const char *name) override {
return optionSet.PropertyType(name);
}
const char *SCI_METHOD DescribeProperty(const char *name) override {
return optionSet.DescribeProperty(name);
}
const char *SCI_METHOD PropertyGet(const char *key) override {
return optionSet.PropertyGet(key);
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override {
if (optionSet.PropertySet(&options, key, val)) {
return 0;
}
return INVALID_POSITION;
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void SCI_METHOD Lex(Sci_PositionU start, Sci_Position length, int initStyle, IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU start, Sci_Position length, int initStyle,IDocument *pAccess) override;
private:
inline bool IsNumber(StyleContext &cxt, const int base = 10) {
return IsADigit(cxt.ch, base) || (IsADigit(cxt.chPrev, base) && numericMetaChars1.Contains(cxt.ch)) ||
(IsADigit(cxt.GetRelative(-2), base) && numericMetaChars2.Contains(cxt.ch));
}
inline bool IsFloat(StyleContext &cxt) {
if (cxt.MatchIgnoreCase("e+") || cxt.MatchIgnoreCase("e-")) {
cxt.Forward();
return true;
}
return ((cxt.chPrev == '.' && IsADigit(cxt.ch)) ||
(IsADigit(cxt.chPrev) && (cxt.ch == '.' || numericMetaChars2.Contains(cxt.ch))));
}
};
Sci_Position SCI_METHOD LexerFSharp::WordListSet(int n, const char *wl) {
WordList *wordListN = nullptr;
Sci_Position firstModification = INVALID_POSITION;
if (n < WORDLIST_SIZE) {
wordListN = &keywords[n];
}
if (wordListN && wordListN->Set(wl)) {
firstModification = 0;
}
return firstModification;
}
void SCI_METHOD LexerFSharp::Lex(Sci_PositionU start, Sci_Position length, int initStyle, IDocument *pAccess) {
LexAccessor styler(pAccess);
StyleContext sc(start, static_cast<Sci_PositionU>(length), initStyle, styler);
Sci_Position lineCurrent = styler.GetLine(static_cast<Sci_Position>(start));
Sci_PositionU cursor = 0;
UnicodeChar uniCh = UnicodeChar();
FSharpString fsStr = FSharpString();
constexpr Sci_Position MAX_WORD_LEN = 64;
constexpr int SPACE = ' ';
int currentBase = 10;
int levelNesting = (lineCurrent >= 1) ? styler.GetLineState(lineCurrent - 1) : 0;
bool isInterpolated = false;
while (sc.More()) {
Sci_PositionU colorSpan = sc.currentPos - 1;
int state = -1;
bool advance = true;
switch (sc.state & 0xff) {
case SCE_FSHARP_DEFAULT:
cursor = sc.currentPos;
if (MatchLineNumberStart(sc)) {
state = SCE_FSHARP_LINENUM;
} else if (MatchPPDirectiveStart(sc)) {
state = SCE_FSHARP_PREPROCESSOR;
} else if (MatchLineComment(sc)) {
state = SCE_FSHARP_COMMENTLINE;
sc.Forward();
sc.ch = SPACE;
} else if (MatchStreamCommentStart(sc)) {
state = SCE_FSHARP_COMMENT;
sc.Forward();
sc.ch = SPACE;
} else if (MatchTypeAttributeStart(sc)) {
state = SCE_FSHARP_ATTRIBUTE;
sc.Forward();
} else if (MatchQuotedExpressionStart(sc)) {
state = SCE_FSHARP_QUOTATION;
sc.Forward();
} else if (MatchCharacterStart(sc)) {
state = SCE_FSHARP_CHARACTER;
} else if (MatchStringStart(sc)) {
fsStr.startChar = sc.ch;
fsStr.nextChar = sc.chNext;
fsStr.startPos = INVALID_POSITION;
if (CanEmbedQuotes(sc)) {
// double quotes after this position should be non-terminating
fsStr.startPos = static_cast<Sci_Position>(sc.currentPos - cursor);
}
if (sc.ch == '`') {
state = SCE_FSHARP_QUOT_IDENTIFIER;
} else if (fsStr.IsVerbatim()) {
state = SCE_FSHARP_VERBATIM;
} else {
state = SCE_FSHARP_STRING;
}
} else if (IsADigit(sc.ch, currentBase) ||
((sc.ch == '+' || sc.ch == '-') && IsADigit(sc.chNext))) {
state = SCE_FSHARP_NUMBER;
} else if (setOperators.Contains(sc.ch) &&
// don't use operator style in async keywords (e.g. `return!`)
!(sc.ch == '!' && iswordstart(sc.chPrev)) &&
// don't use operator style in member access, array/string indexing
!(sc.ch == '.' && (sc.chPrev == '\"' || iswordstart(sc.chPrev)) &&
(iswordstart(sc.chNext) || sc.chNext == '['))) {
state = SCE_FSHARP_OPERATOR;
} else if (iswordstart(sc.ch)) {
state = SCE_FSHARP_IDENTIFIER;
} else {
state = SCE_FSHARP_DEFAULT;
}
break;
case SCE_FSHARP_LINENUM:
case SCE_FSHARP_PREPROCESSOR:
case SCE_FSHARP_COMMENTLINE:
if (sc.MatchLineEnd()) {
state = SCE_FSHARP_DEFAULT;
advance = false;
}
break;
case SCE_FSHARP_COMMENT:
if (MatchStreamCommentStart(sc)) {
sc.Forward();
sc.ch = SPACE;
levelNesting++;
} else if (MatchStreamCommentEnd(sc)) {
if (levelNesting > 0)
levelNesting--;
else {
state = SCE_FSHARP_DEFAULT;
colorSpan++;
}
}
break;
case SCE_FSHARP_ATTRIBUTE:
case SCE_FSHARP_QUOTATION:
if (MatchTypeAttributeEnd(sc) || MatchQuotedExpressionEnd(sc)) {
state = SCE_FSHARP_DEFAULT;
colorSpan++;
}
break;
case SCE_FSHARP_CHARACTER:
if (sc.chPrev == '\\' && sc.GetRelative(-2) != '\\') {
uniCh = UnicodeChar(sc.ch);
} else if (sc.ch == '\'' &&
((sc.chPrev == ' ' && sc.GetRelative(-2) == '\'') || sc.chPrev != '\\' ||
(sc.chPrev == '\\' && sc.GetRelative(-2) == '\\'))) {
// byte literal?
if (sc.Match('\'', 'B')) {
sc.Forward();
colorSpan++;
}
if (!sc.atLineEnd) {
colorSpan++;
} else {
sc.ChangeState(SCE_FSHARP_IDENTIFIER);
}
state = SCE_FSHARP_DEFAULT;
} else {
uniCh.Parse(sc.ch);
if (uniCh.AtEnd() && (sc.currentPos - cursor) >= 2) {
// terminate now, since we left the char behind
sc.ChangeState(SCE_FSHARP_IDENTIFIER);
advance = false;
}
}
break;
case SCE_FSHARP_STRING:
case SCE_FSHARP_VERBATIM:
case SCE_FSHARP_QUOT_IDENTIFIER:
if (MatchStringEnd(sc, fsStr)) {
const Sci_Position strLen = static_cast<Sci_Position>(sc.currentPos - cursor);
// backtrack to start of string
for (Sci_Position i = -strLen; i < 0; i++) {
const int startQuote = sc.GetRelative(i);
if (startQuote == '\"' || (startQuote == '`' && sc.GetRelative(i - 1) == '`')) {
// byte array?
if (sc.Match('\"', 'B')) {
sc.Forward();
colorSpan++;
}
if (!sc.atLineEnd) {
colorSpan++;
} else {
sc.ChangeState(SCE_FSHARP_IDENTIFIER);
}
state = SCE_FSHARP_DEFAULT;
break;
}
}
} else if (sc.ch == '%' &&
!(fsStr.startChar == '`' || sc.MatchIgnoreCase("% ") || sc.MatchIgnoreCase("% \"")) &&
(setFormatSpecs.Contains(sc.chNext) || setFormatFlags.Contains(sc.chNext))) {
if (fsStr.CanInterpolate() && sc.chNext != '%') {
for (Sci_Position i = 2; i < length && !IsLineEnd(sc, i); i++) {
if (sc.GetRelative(i) == '{') {
state = setFormatSpecs.Contains(sc.GetRelative(i - 1))
? SCE_FSHARP_FORMAT_SPEC
: state;
break;
}
}
} else {
state = SCE_FSHARP_FORMAT_SPEC;
}
} else if (isInterpolated) {
if (sc.ch == ',') {
// .NET alignment specifier?
state = (sc.chNext == '+' || sc.chNext == '-' || IsADigit(sc.chNext))
? SCE_FSHARP_FORMAT_SPEC
: state;
} else if (sc.ch == ':') {
// .NET format specifier?
state = setDotNetFormatSpecs.Contains(sc.chNext)
? SCE_FSHARP_FORMAT_SPEC
: state;
} else if (sc.chNext == '}') {
isInterpolated = false;
sc.Forward();
state = fsStr.IsVerbatim() ? SCE_FSHARP_VERBATIM : SCE_FSHARP_STRING;
}
} else if (fsStr.CanInterpolate() && sc.ch == '{') {
isInterpolated = true;
}
break;
case SCE_FSHARP_IDENTIFIER:
if (!(iswordstart(sc.ch) || sc.ch == '\'')) {
const Sci_Position wordLen = static_cast<Sci_Position>(sc.currentPos - cursor);
if (wordLen < MAX_WORD_LEN) {
// wordLength is believable as keyword, [re-]construct token - RR
char token[MAX_WORD_LEN] = { 0 };
for (Sci_Position i = -wordLen; i < 0; i++) {
token[wordLen + i] = static_cast<char>(sc.GetRelative(i));
}
token[wordLen] = '\0';
// a snake_case_identifier can never be a keyword
if (!(sc.ch == '_' || sc.GetRelative(-wordLen - 1) == '_')) {
for (int i = 0; i < WORDLIST_SIZE; i++) {
if (keywords[i].InList(token)) {
sc.ChangeState(keywordClasses[i]);
break;
}
}
}
}
state = SCE_FSHARP_DEFAULT;
advance = false;
}
break;
case SCE_FSHARP_OPERATOR:
// special-case "()" and "[]" tokens as KEYWORDS - RR
if ((sc.ch == ')' && sc.chPrev == '(') || (sc.ch == ']' && sc.chPrev == '[')) {
sc.ChangeState(SCE_FSHARP_KEYWORD);
colorSpan++;
} else {
advance = false;
}
state = SCE_FSHARP_DEFAULT;
break;
case SCE_FSHARP_NUMBER:
if ((setOperators.Contains(sc.chPrev) || IsASpaceOrTab(sc.chPrev)) && sc.ch == '0') {
if (numericPrefixes.find(sc.chNext) != numericPrefixes.end()) {
currentBase = numericPrefixes[sc.chNext];
sc.Forward(2);
}
} else if ((setOperators.Contains(sc.GetRelative(-2)) || IsASpaceOrTab(sc.GetRelative(-2))) &&
sc.chPrev == '0') {
if (numericPrefixes.find(sc.ch) != numericPrefixes.end()) {
currentBase = numericPrefixes[sc.ch];
sc.Forward();
}
}
state = (IsNumber(sc, currentBase) || IsFloat(sc))
? SCE_FSHARP_NUMBER
// change style even when operators aren't spaced
: setOperators.Contains(sc.ch) ? SCE_FSHARP_OPERATOR : SCE_FSHARP_DEFAULT;
currentBase = (state == SCE_FSHARP_NUMBER) ? currentBase : 10;
break;
case SCE_FSHARP_FORMAT_SPEC:
if (!(isInterpolated && IsADigit(sc.chNext)) &&
(!setFormatSpecs.Contains(sc.chNext) ||
!(setFormatFlags.Contains(sc.ch) || IsADigit(sc.ch)) ||
(setFormatFlags.Contains(sc.ch) && sc.ch == sc.chNext))) {
colorSpan++;
state = fsStr.IsVerbatim() ? SCE_FSHARP_VERBATIM : SCE_FSHARP_STRING;
}
break;
}
if (sc.MatchLineEnd()) {
styler.SetLineState(lineCurrent++, (sc.state == SCE_FSHARP_COMMENT) ? levelNesting : 0);
advance = true;
}
if (state >= SCE_FSHARP_DEFAULT) {
styler.ColourTo(colorSpan, sc.state);
sc.ChangeState(state);
}
if (advance) {
sc.Forward();
}
}
sc.Complete();
}
bool LineContains(LexAccessor &styler, const char *word, const Sci_Position start,
const int chAttr = SCE_FSHARP_DEFAULT);
void FoldLexicalGroup(LexAccessor &styler, int &levelNext, const Sci_Position lineCurrent, const char *word,
const int chAttr);
void SCI_METHOD LexerFSharp::Fold(Sci_PositionU start, Sci_Position length, int initStyle, IDocument *pAccess) {
if (!options.fold) {
return;
}
LexAccessor styler(pAccess);
const Sci_Position startPos = static_cast<Sci_Position>(start);
const Sci_PositionU endPos = start + length;
Sci_Position lineCurrent = styler.GetLine(startPos);
Sci_Position lineNext = lineCurrent + 1;
Sci_Position lineStartNext = styler.LineStart(lineNext);
int style = initStyle;
int styleNext = styler.StyleAt(startPos);
char chNext = styler[startPos];
int levelNext;
int levelCurrent = SC_FOLDLEVELBASE;
int visibleChars = 0;
if (lineCurrent > 0) {
levelCurrent = styler.LevelAt(lineCurrent - 1) >> 0x10;
}
levelNext = levelCurrent;
for (Sci_PositionU i = start; i < endPos; i++) {
const Sci_Position currentPos = static_cast<Sci_Position>(i);
const bool atEOL = (currentPos == (lineStartNext - 1) || styler.SafeGetCharAt(currentPos) == '\r');
const bool atLineOrDocEnd = (atEOL || (i == (endPos - 1)));
const int stylePrev = style;
const char ch = chNext;
const bool inLineComment = (stylePrev == SCE_FSHARP_COMMENTLINE);
style = styleNext;
styleNext = styler.StyleAt(currentPos + 1);
chNext = styler.SafeGetCharAt(currentPos + 1);
if (options.foldComment) {
if (options.foldCommentMultiLine && inLineComment && atEOL) {
FoldLexicalGroup(styler, levelNext, lineCurrent, "//", SCE_FSHARP_COMMENTLINE);
}
if (options.foldCommentStream && style == SCE_FSHARP_COMMENT && !inLineComment) {
if (stylePrev != SCE_FSHARP_COMMENT ||
(styler.Match(currentPos, "(*") &&
!LineContains(styler, "*)", currentPos + 2, SCE_FSHARP_COMMENT))) {
levelNext++;
} else if ((styleNext != SCE_FSHARP_COMMENT ||
((styler.Match(currentPos, "*)") &&
!LineContains(styler, "(*", styler.LineStart(lineCurrent), SCE_FSHARP_COMMENT)) &&
styler.GetLineState(lineCurrent - 1) > 0)) &&
!atEOL) {
levelNext--;
}
}
}
if (options.foldPreprocessor && style == SCE_FSHARP_PREPROCESSOR) {
if (styler.Match(currentPos, "#if")) {
levelNext++;
} else if (styler.Match(currentPos, "#endif")) {
levelNext--;
}
}
if (options.foldImports && styler.Match(currentPos, "open ") && styleNext == SCE_FSHARP_KEYWORD) {
FoldLexicalGroup(styler, levelNext, lineCurrent, "open ", SCE_FSHARP_KEYWORD);
}
if (!IsASpace(ch)) {
visibleChars++;
}
if (atLineOrDocEnd) {
int levelUse = levelCurrent;
int lev = levelUse | levelNext << 16;
if (visibleChars == 0 && options.foldCompact) {
lev |= SC_FOLDLEVELWHITEFLAG;
}
if (levelUse < levelNext) {
lev |= SC_FOLDLEVELHEADERFLAG;
}
if (lev != styler.LevelAt(lineCurrent)) {
styler.SetLevel(lineCurrent, lev);
}
visibleChars = 0;
lineCurrent++;
lineNext = lineCurrent + 1;
lineStartNext = styler.LineStart(lineNext);
levelCurrent = levelNext;
if (atEOL && (currentPos == (styler.Length() - 1))) {
styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
}
}
}
}
bool LineContains(LexAccessor &styler, const char *word, const Sci_Position start, const int chAttr) {
bool found = false;
bool requireStyle = (chAttr > SCE_FSHARP_DEFAULT);
for (Sci_Position i = start; i < styler.LineStart(styler.GetLine(start) + 1) - 1; i++) {
if (styler.Match(i, word)) {
found = requireStyle ? styler.StyleAt(i) == chAttr : true;
break;
}
}
return found;
}
void FoldLexicalGroup(LexAccessor &styler, int &levelNext, const Sci_Position lineCurrent, const char *word,
const int chAttr) {
const Sci_Position linePrev = styler.LineStart(lineCurrent - 1);
const Sci_Position lineNext = styler.LineStart(lineCurrent + 1);
const bool follows = (lineCurrent > 0) && LineContains(styler, word, linePrev, chAttr);
const bool isFollowed = LineContains(styler, word, lineNext, chAttr);
if (isFollowed && !follows) {
levelNext++;
} else if (!isFollowed && follows && levelNext > SC_FOLDLEVELBASE) {
levelNext--;
}
}
} // namespace
LexerModule lmFSharp(SCLEX_FSHARP, LexerFSharp::LexerFactoryFSharp, "fsharp", fsharpWordLists);

View File

@ -0,0 +1,355 @@
// Scintilla source code edit control
/** @file LexFlagship.cxx
** Lexer for Harbour and FlagShip.
** (Syntactically compatible to other xBase dialects, like Clipper, dBase, Clip, FoxPro etc.)
**/
// Copyright 2005 by Randy Butler
// Copyright 2010 by Xavi <jarabal/at/gmail.com> (Harbour)
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// 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;
// Extended to accept accented characters
static inline bool IsAWordChar(int ch)
{
return ch >= 0x80 ||
(isalnum(ch) || ch == '_');
}
static void ColouriseFlagShipDoc(Sci_PositionU startPos, Sci_Position 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];
// property lexer.flagship.styling.within.preprocessor
// For Harbour code, determines whether all preprocessor code is styled in the preprocessor style (0) or only from the
// initial # to the end of the command word(1, the default). It also determines how to present text, dump, and disabled code.
bool stylingWithinPreprocessor = styler.GetPropertyInt("lexer.flagship.styling.within.preprocessor", 1) != 0;
CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]");
int visibleChars = 0;
int closeStringChar = 0;
int styleBeforeDCKeyword = SCE_FS_DEFAULT;
bool bEnableCode = initStyle < SCE_FS_DISABLEDCODE;
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
// Determine if the current state should terminate.
switch (sc.state) {
case SCE_FS_OPERATOR:
case SCE_FS_OPERATOR_C:
case SCE_FS_WORDOPERATOR:
sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C);
break;
case SCE_FS_IDENTIFIER:
case SCE_FS_IDENTIFIER_C:
if (!IsAWordChar(sc.ch)) {
char s[64];
sc.GetCurrentLowered(s, sizeof(s));
if (keywords.InList(s)) {
sc.ChangeState(bEnableCode ? SCE_FS_KEYWORD : SCE_FS_KEYWORD_C);
} else if (keywords2.InList(s)) {
sc.ChangeState(bEnableCode ? SCE_FS_KEYWORD2 : SCE_FS_KEYWORD2_C);
} else if (bEnableCode && keywords3.InList(s)) {
sc.ChangeState(SCE_FS_KEYWORD3);
} else if (bEnableCode && keywords4.InList(s)) {
sc.ChangeState(SCE_FS_KEYWORD4);
}// Else, it is really an identifier...
sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C);
}
break;
case SCE_FS_NUMBER:
if (!IsAWordChar(sc.ch) && !(sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_FS_DEFAULT);
}
break;
case SCE_FS_NUMBER_C:
if (!IsAWordChar(sc.ch) && sc.ch != '.') {
sc.SetState(SCE_FS_DEFAULT_C);
}
break;
case SCE_FS_CONSTANT:
if (!IsAWordChar(sc.ch)) {
sc.SetState(SCE_FS_DEFAULT);
}
break;
case SCE_FS_STRING:
case SCE_FS_STRING_C:
if (sc.ch == closeStringChar) {
sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C);
} else if (sc.atLineEnd) {
sc.ChangeState(bEnableCode ? SCE_FS_STRINGEOL : SCE_FS_STRINGEOL_C);
}
break;
case SCE_FS_STRINGEOL:
case SCE_FS_STRINGEOL_C:
if (sc.atLineStart) {
sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C);
}
break;
case SCE_FS_COMMENTDOC:
case SCE_FS_COMMENTDOC_C:
if (sc.Match('*', '/')) {
sc.Forward();
sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C);
} 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))) {
styleBeforeDCKeyword = bEnableCode ? SCE_FS_COMMENTDOC : SCE_FS_COMMENTDOC_C;
sc.SetState(SCE_FS_COMMENTDOCKEYWORD);
}
}
break;
case SCE_FS_COMMENT:
case SCE_FS_COMMENTLINE:
if (sc.atLineStart) {
sc.SetState(SCE_FS_DEFAULT);
}
break;
case SCE_FS_COMMENTLINEDOC:
case SCE_FS_COMMENTLINEDOC_C:
if (sc.atLineStart) {
sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C);
} 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 == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) {
styleBeforeDCKeyword = bEnableCode ? SCE_FS_COMMENTLINEDOC : SCE_FS_COMMENTLINEDOC_C;
sc.SetState(SCE_FS_COMMENTDOCKEYWORD);
}
}
break;
case SCE_FS_COMMENTDOCKEYWORD:
if ((styleBeforeDCKeyword == SCE_FS_COMMENTDOC || styleBeforeDCKeyword == SCE_FS_COMMENTDOC_C) &&
sc.Match('*', '/')) {
sc.ChangeState(SCE_FS_COMMENTDOCKEYWORDERROR);
sc.Forward();
sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C);
} else if (!setDoxygen.Contains(sc.ch)) {
char s[64];
sc.GetCurrentLowered(s, sizeof(s));
if (!IsASpace(sc.ch) || !keywords5.InList(s + 1)) {
sc.ChangeState(SCE_FS_COMMENTDOCKEYWORDERROR);
}
sc.SetState(styleBeforeDCKeyword);
}
break;
case SCE_FS_PREPROCESSOR:
case SCE_FS_PREPROCESSOR_C:
if (sc.atLineEnd) {
if (!(sc.chPrev == ';' || sc.GetRelative(-2) == ';')) {
sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C);
}
} else if (stylingWithinPreprocessor) {
if (IsASpaceOrTab(sc.ch)) {
sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C);
}
} else if (sc.Match('/', '*') || sc.Match('/', '/') || sc.Match('&', '&')) {
sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C);
}
break;
case SCE_FS_DISABLEDCODE:
if (sc.ch == '#' && visibleChars == 0) {
sc.SetState(bEnableCode ? SCE_FS_PREPROCESSOR : SCE_FS_PREPROCESSOR_C);
do { // Skip whitespace between # and preprocessor word
sc.Forward();
} while (IsASpaceOrTab(sc.ch) && sc.More());
if (sc.MatchIgnoreCase("pragma")) {
sc.Forward(6);
do { // Skip more whitespace until keyword
sc.Forward();
} while (IsASpaceOrTab(sc.ch) && sc.More());
if (sc.MatchIgnoreCase("enddump") || sc.MatchIgnoreCase("__endtext")) {
bEnableCode = true;
sc.SetState(SCE_FS_DISABLEDCODE);
sc.Forward(sc.ch == '_' ? 8 : 6);
sc.ForwardSetState(SCE_FS_DEFAULT);
} else {
sc.ChangeState(SCE_FS_DISABLEDCODE);
}
} else {
sc.ChangeState(SCE_FS_DISABLEDCODE);
}
}
break;
case SCE_FS_DATE:
if (sc.ch == '}') {
sc.ForwardSetState(SCE_FS_DEFAULT);
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_FS_STRINGEOL);
}
}
// Determine if a new state should be entered.
if (sc.state == SCE_FS_DEFAULT || sc.state == SCE_FS_DEFAULT_C) {
if (bEnableCode &&
(sc.MatchIgnoreCase(".and.") || sc.MatchIgnoreCase(".not."))) {
sc.SetState(SCE_FS_WORDOPERATOR);
sc.Forward(4);
} else if (bEnableCode && sc.MatchIgnoreCase(".or.")) {
sc.SetState(SCE_FS_WORDOPERATOR);
sc.Forward(3);
} else if (bEnableCode &&
(sc.MatchIgnoreCase(".t.") || sc.MatchIgnoreCase(".f.") ||
(!IsAWordChar(sc.GetRelative(3)) && sc.MatchIgnoreCase("nil")))) {
sc.SetState(SCE_FS_CONSTANT);
sc.Forward(2);
} else if (sc.Match('/', '*')) {
sc.SetState(bEnableCode ? SCE_FS_COMMENTDOC : SCE_FS_COMMENTDOC_C);
sc.Forward();
} else if (bEnableCode && sc.Match('&', '&')) {
sc.SetState(SCE_FS_COMMENTLINE);
sc.Forward();
} else if (sc.Match('/', '/')) {
sc.SetState(bEnableCode ? SCE_FS_COMMENTLINEDOC : SCE_FS_COMMENTLINEDOC_C);
sc.Forward();
} else if (bEnableCode && sc.ch == '*' && visibleChars == 0) {
sc.SetState(SCE_FS_COMMENT);
} else if (sc.ch == '\"' || sc.ch == '\'') {
sc.SetState(bEnableCode ? SCE_FS_STRING : SCE_FS_STRING_C);
closeStringChar = sc.ch;
} else if (closeStringChar == '>' && sc.ch == '<') {
sc.SetState(bEnableCode ? SCE_FS_STRING : SCE_FS_STRING_C);
} else if (sc.ch == '#' && visibleChars == 0) {
sc.SetState(bEnableCode ? SCE_FS_PREPROCESSOR : SCE_FS_PREPROCESSOR_C);
do { // Skip whitespace between # and preprocessor word
sc.Forward();
} while (IsASpaceOrTab(sc.ch) && sc.More());
if (sc.atLineEnd) {
sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C);
} else if (sc.MatchIgnoreCase("include")) {
if (stylingWithinPreprocessor) {
closeStringChar = '>';
}
} else if (sc.MatchIgnoreCase("pragma")) {
sc.Forward(6);
do { // Skip more whitespace until keyword
sc.Forward();
} while (IsASpaceOrTab(sc.ch) && sc.More());
if (sc.MatchIgnoreCase("begindump") || sc.MatchIgnoreCase("__cstream")) {
bEnableCode = false;
if (stylingWithinPreprocessor) {
sc.SetState(SCE_FS_DISABLEDCODE);
sc.Forward(8);
sc.ForwardSetState(SCE_FS_DEFAULT_C);
} else {
sc.SetState(SCE_FS_DISABLEDCODE);
}
} else if (sc.MatchIgnoreCase("enddump") || sc.MatchIgnoreCase("__endtext")) {
bEnableCode = true;
sc.SetState(SCE_FS_DISABLEDCODE);
sc.Forward(sc.ch == '_' ? 8 : 6);
sc.ForwardSetState(SCE_FS_DEFAULT);
}
}
} else if (bEnableCode && sc.ch == '{') {
Sci_Position p = 0;
int chSeek;
Sci_PositionU endPos(startPos + length);
do { // Skip whitespace
chSeek = sc.GetRelative(++p);
} while (IsASpaceOrTab(chSeek) && (sc.currentPos + p < endPos));
if (chSeek == '^') {
sc.SetState(SCE_FS_DATE);
} else {
sc.SetState(SCE_FS_OPERATOR);
}
} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(bEnableCode ? SCE_FS_NUMBER : SCE_FS_NUMBER_C);
} else if (IsAWordChar(sc.ch)) {
sc.SetState(bEnableCode ? SCE_FS_IDENTIFIER : SCE_FS_IDENTIFIER_C);
} else if (isoperator(static_cast<char>(sc.ch)) || (bEnableCode && sc.ch == '@')) {
sc.SetState(bEnableCode ? SCE_FS_OPERATOR : SCE_FS_OPERATOR_C);
}
}
if (sc.atLineEnd) {
visibleChars = 0;
closeStringChar = 0;
}
if (!IsASpace(sc.ch)) {
visibleChars++;
}
}
sc.Complete();
}
static void FoldFlagShipDoc(Sci_PositionU startPos, Sci_Position length, int,
WordList *[], Accessor &styler)
{
Sci_Position endPos = startPos + length;
// Backtrack to previous line in case need to fix its fold status
Sci_Position lineCurrent = styler.GetLine(startPos);
if (startPos > 0 && lineCurrent > 0) {
lineCurrent--;
startPos = styler.LineStart(lineCurrent);
}
int spaceFlags = 0;
int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags);
char chNext = styler[startPos];
for (Sci_Position i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos-1)) {
int lev = indentCurrent;
int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags);
if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
lev |= SC_FOLDLEVELHEADERFLAG;
} else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
int spaceFlags2 = 0;
int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2);
if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
lev |= SC_FOLDLEVELHEADERFLAG;
}
}
}
indentCurrent = indentNext;
styler.SetLevel(lineCurrent, lev);
lineCurrent++;
}
}
}
static const char * const FSWordListDesc[] = {
"Keywords Commands",
"Std Library Functions",
"Procedure, return, exit",
"Class (oop)",
"Doxygen keywords",
0
};
LexerModule lmFlagShip(SCLEX_FLAGSHIP, ColouriseFlagShipDoc, "flagship", FoldFlagShipDoc, FSWordListDesc);

View File

@ -0,0 +1,171 @@
// Scintilla source code edit control
/** @file LexForth.cxx
** Lexer for FORTH
**/
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// 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;
static inline bool IsAWordStart(int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.');
}
static inline bool IsANumChar(int ch) {
return (ch < 0x80) && (isxdigit(ch) || ch == '.' || ch == 'e' || ch == 'E' );
}
static inline bool IsASpaceChar(int ch) {
return (ch < 0x80) && isspace(ch);
}
static void ColouriseForthDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordLists[],
Accessor &styler) {
WordList &control = *keywordLists[0];
WordList &keyword = *keywordLists[1];
WordList &defword = *keywordLists[2];
WordList &preword1 = *keywordLists[3];
WordList &preword2 = *keywordLists[4];
WordList &strings = *keywordLists[5];
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward())
{
// Determine if the current state should terminate.
if (sc.state == SCE_FORTH_COMMENT) {
if (sc.atLineEnd) {
sc.SetState(SCE_FORTH_DEFAULT);
}
}else if (sc.state == SCE_FORTH_COMMENT_ML) {
if (sc.ch == ')') {
sc.ForwardSetState(SCE_FORTH_DEFAULT);
}
}else if (sc.state == SCE_FORTH_IDENTIFIER || sc.state == SCE_FORTH_NUMBER) {
// handle numbers here too, because what we thought was a number might
// turn out to be a keyword e.g. 2DUP
if (IsASpaceChar(sc.ch) ) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
int newState = sc.state == SCE_FORTH_NUMBER ? SCE_FORTH_NUMBER : SCE_FORTH_DEFAULT;
if (control.InList(s)) {
sc.ChangeState(SCE_FORTH_CONTROL);
} else if (keyword.InList(s)) {
sc.ChangeState(SCE_FORTH_KEYWORD);
} else if (defword.InList(s)) {
sc.ChangeState(SCE_FORTH_DEFWORD);
} else if (preword1.InList(s)) {
sc.ChangeState(SCE_FORTH_PREWORD1);
} else if (preword2.InList(s)) {
sc.ChangeState(SCE_FORTH_PREWORD2);
} else if (strings.InList(s)) {
sc.ChangeState(SCE_FORTH_STRING);
newState = SCE_FORTH_STRING;
}
sc.SetState(newState);
}
if (sc.state == SCE_FORTH_NUMBER) {
if (IsASpaceChar(sc.ch)) {
sc.SetState(SCE_FORTH_DEFAULT);
} else if (!IsANumChar(sc.ch)) {
sc.ChangeState(SCE_FORTH_IDENTIFIER);
}
}
}else if (sc.state == SCE_FORTH_STRING) {
if (sc.ch == '\"') {
sc.ForwardSetState(SCE_FORTH_DEFAULT);
}
}else if (sc.state == SCE_FORTH_LOCALE) {
if (sc.ch == '}') {
sc.ForwardSetState(SCE_FORTH_DEFAULT);
}
}else if (sc.state == SCE_FORTH_DEFWORD) {
if (IsASpaceChar(sc.ch)) {
sc.SetState(SCE_FORTH_DEFAULT);
}
}
// Determine if a new state should be entered.
if (sc.state == SCE_FORTH_DEFAULT) {
if (sc.ch == '\\'){
sc.SetState(SCE_FORTH_COMMENT);
} else if (sc.ch == '(' &&
(sc.atLineStart || IsASpaceChar(sc.chPrev)) &&
(sc.atLineEnd || IsASpaceChar(sc.chNext))) {
sc.SetState(SCE_FORTH_COMMENT_ML);
} else if ( (sc.ch == '$' && (IsASCII(sc.chNext) && isxdigit(sc.chNext))) ) {
// number starting with $ is a hex number
sc.SetState(SCE_FORTH_NUMBER);
while(sc.More() && IsASCII(sc.chNext) && isxdigit(sc.chNext))
sc.Forward();
} else if ( (sc.ch == '%' && (IsASCII(sc.chNext) && (sc.chNext == '0' || sc.chNext == '1'))) ) {
// number starting with % is binary
sc.SetState(SCE_FORTH_NUMBER);
while(sc.More() && IsASCII(sc.chNext) && (sc.chNext == '0' || sc.chNext == '1'))
sc.Forward();
} else if ( IsASCII(sc.ch) &&
(isxdigit(sc.ch) || ((sc.ch == '.' || sc.ch == '-') && IsASCII(sc.chNext) && isxdigit(sc.chNext)) )
){
sc.SetState(SCE_FORTH_NUMBER);
} else if (IsAWordStart(sc.ch)) {
sc.SetState(SCE_FORTH_IDENTIFIER);
} else if (sc.ch == '{') {
sc.SetState(SCE_FORTH_LOCALE);
} else if (sc.ch == ':' && IsASCII(sc.chNext) && isspace(sc.chNext)) {
// highlight word definitions e.g. : GCD ( n n -- n ) ..... ;
// ^ ^^^
sc.SetState(SCE_FORTH_DEFWORD);
while(sc.More() && IsASCII(sc.chNext) && isspace(sc.chNext))
sc.Forward();
} else if (sc.ch == ';' &&
(sc.atLineStart || IsASpaceChar(sc.chPrev)) &&
(sc.atLineEnd || IsASpaceChar(sc.chNext)) ) {
// mark the ';' that ends a word
sc.SetState(SCE_FORTH_DEFWORD);
sc.ForwardSetState(SCE_FORTH_DEFAULT);
}
}
}
sc.Complete();
}
static void FoldForthDoc(Sci_PositionU, Sci_Position, int, WordList *[],
Accessor &) {
}
static const char * const forthWordLists[] = {
"control keywords",
"keywords",
"definition words",
"prewords with one argument",
"prewords with two arguments",
"string definition keywords",
0,
};
LexerModule lmForth(SCLEX_FORTH, ColouriseForthDoc, "forth", FoldForthDoc, forthWordLists);

View File

@ -0,0 +1,724 @@
// Scintilla source code edit control
/** @file LexFortran.cxx
** Lexer for Fortran.
** Written by Chuan-jian Shen, Last changed Sep. 2003
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// 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;
/***********************************************/
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '%');
}
/**********************************************/
static inline bool IsAWordStart(const int ch) {
return (ch < 0x80) && (isalnum(ch));
}
/***************************************/
static inline bool IsABlank(unsigned int ch) {
return (ch == ' ') || (ch == 0x09) || (ch == 0x0b) ;
}
/***************************************/
static inline bool IsALineEnd(char ch) {
return ((ch == '\n') || (ch == '\r')) ;
}
/***************************************/
static Sci_PositionU GetContinuedPos(Sci_PositionU pos, Accessor &styler) {
while (!IsALineEnd(styler.SafeGetCharAt(pos++))) continue;
if (styler.SafeGetCharAt(pos) == '\n') pos++;
while (IsABlank(styler.SafeGetCharAt(pos++))) continue;
char chCur = styler.SafeGetCharAt(pos);
if (chCur == '&') {
while (IsABlank(styler.SafeGetCharAt(++pos))) continue;
return pos;
} else {
return pos;
}
}
/***************************************/
static void ColouriseFortranDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler, bool isFixFormat) {
WordList &keywords = *keywordlists[0];
WordList &keywords2 = *keywordlists[1];
WordList &keywords3 = *keywordlists[2];
/***************************************/
Sci_Position posLineStart = 0;
int numNonBlank = 0, prevState = 0;
Sci_Position endPos = startPos + length;
/***************************************/
// backtrack to the nearest keyword
while ((startPos > 1) && (styler.StyleAt(startPos) != SCE_F_WORD)) {
startPos--;
}
startPos = styler.LineStart(styler.GetLine(startPos));
initStyle = styler.StyleAt(startPos - 1);
StyleContext sc(startPos, endPos-startPos, initStyle, styler);
/***************************************/
for (; sc.More(); sc.Forward()) {
// remember the start position of the line
if (sc.atLineStart) {
posLineStart = sc.currentPos;
numNonBlank = 0;
sc.SetState(SCE_F_DEFAULT);
}
if (!IsASpaceOrTab(sc.ch)) numNonBlank ++;
/***********************************************/
// Handle the fix format generically
Sci_Position toLineStart = sc.currentPos - posLineStart;
if (isFixFormat && (toLineStart < 6 || toLineStart >= 72)) {
if ((toLineStart == 0 && (tolower(sc.ch) == 'c' || sc.ch == '*')) || sc.ch == '!') {
if (sc.MatchIgnoreCase("cdec$") || sc.MatchIgnoreCase("*dec$") || sc.MatchIgnoreCase("!dec$") ||
sc.MatchIgnoreCase("cdir$") || sc.MatchIgnoreCase("*dir$") || sc.MatchIgnoreCase("!dir$") ||
sc.MatchIgnoreCase("cms$") || sc.MatchIgnoreCase("*ms$") || sc.MatchIgnoreCase("!ms$") ||
sc.chNext == '$') {
sc.SetState(SCE_F_PREPROCESSOR);
} else {
sc.SetState(SCE_F_COMMENT);
}
while (!sc.atLineEnd && sc.More()) sc.Forward(); // Until line end
} else if (toLineStart >= 72) {
sc.SetState(SCE_F_COMMENT);
while (!sc.atLineEnd && sc.More()) sc.Forward(); // Until line end
} else if (toLineStart < 5) {
if (IsADigit(sc.ch))
sc.SetState(SCE_F_LABEL);
else
sc.SetState(SCE_F_DEFAULT);
} else if (toLineStart == 5) {
//if (!IsASpace(sc.ch) && sc.ch != '0') {
if (sc.ch != '\r' && sc.ch != '\n') {
sc.SetState(SCE_F_CONTINUATION);
if (!IsASpace(sc.ch) && sc.ch != '0')
sc.ForwardSetState(prevState);
} else
sc.SetState(SCE_F_DEFAULT);
}
continue;
}
/***************************************/
// Handle line continuation generically.
if (!isFixFormat && sc.ch == '&' && sc.state != SCE_F_COMMENT) {
char chTemp = ' ';
Sci_Position j = 1;
while (IsABlank(chTemp) && j<132) {
chTemp = static_cast<char>(sc.GetRelative(j));
j++;
}
if (chTemp == '!') {
sc.SetState(SCE_F_CONTINUATION);
if (sc.chNext == '!') sc.ForwardSetState(SCE_F_COMMENT);
} else if (chTemp == '\r' || chTemp == '\n') {
int currentState = sc.state;
sc.SetState(SCE_F_CONTINUATION);
sc.ForwardSetState(SCE_F_DEFAULT);
while (IsASpace(sc.ch) && sc.More()) {
sc.Forward();
if (sc.atLineStart) numNonBlank = 0;
if (!IsASpaceOrTab(sc.ch)) numNonBlank ++;
}
if (sc.ch == '&') {
sc.SetState(SCE_F_CONTINUATION);
sc.Forward();
}
sc.SetState(currentState);
}
}
/***************************************/
// Hanndle preprocessor directives
if (sc.ch == '#' && numNonBlank == 1)
{
sc.SetState(SCE_F_PREPROCESSOR);
while (!sc.atLineEnd && sc.More())
sc.Forward(); // Until line end
}
/***************************************/
// Determine if the current state should terminate.
if (sc.state == SCE_F_OPERATOR) {
sc.SetState(SCE_F_DEFAULT);
} else if (sc.state == SCE_F_NUMBER) {
if (!(IsAWordChar(sc.ch) || sc.ch=='\'' || sc.ch=='\"' || sc.ch=='.')) {
sc.SetState(SCE_F_DEFAULT);
}
} else if (sc.state == SCE_F_IDENTIFIER) {
if (!IsAWordChar(sc.ch) || (sc.ch == '%')) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
if (keywords.InList(s)) {
sc.ChangeState(SCE_F_WORD);
} else if (keywords2.InList(s)) {
sc.ChangeState(SCE_F_WORD2);
} else if (keywords3.InList(s)) {
sc.ChangeState(SCE_F_WORD3);
}
sc.SetState(SCE_F_DEFAULT);
}
} else if (sc.state == SCE_F_COMMENT || sc.state == SCE_F_PREPROCESSOR) {
if (sc.ch == '\r' || sc.ch == '\n') {
sc.SetState(SCE_F_DEFAULT);
}
} else if (sc.state == SCE_F_STRING1) {
prevState = sc.state;
if (sc.ch == '\'') {
if (sc.chNext == '\'') {
sc.Forward();
} else {
sc.ForwardSetState(SCE_F_DEFAULT);
prevState = SCE_F_DEFAULT;
}
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_F_STRINGEOL);
sc.ForwardSetState(SCE_F_DEFAULT);
}
} else if (sc.state == SCE_F_STRING2) {
prevState = sc.state;
if (sc.atLineEnd) {
sc.ChangeState(SCE_F_STRINGEOL);
sc.ForwardSetState(SCE_F_DEFAULT);
} else if (sc.ch == '\"') {
if (sc.chNext == '\"') {
sc.Forward();
} else {
sc.ForwardSetState(SCE_F_DEFAULT);
prevState = SCE_F_DEFAULT;
}
}
} else if (sc.state == SCE_F_OPERATOR2) {
if (sc.ch == '.') {
sc.ForwardSetState(SCE_F_DEFAULT);
}
} else if (sc.state == SCE_F_CONTINUATION) {
sc.SetState(SCE_F_DEFAULT);
} else if (sc.state == SCE_F_LABEL) {
if (!IsADigit(sc.ch)) {
sc.SetState(SCE_F_DEFAULT);
} else {
if (isFixFormat && sc.currentPos-posLineStart > 4)
sc.SetState(SCE_F_DEFAULT);
else if (numNonBlank > 5)
sc.SetState(SCE_F_DEFAULT);
}
}
/***************************************/
// Determine if a new state should be entered.
if (sc.state == SCE_F_DEFAULT) {
if (sc.ch == '!') {
if (sc.MatchIgnoreCase("!dec$") || sc.MatchIgnoreCase("!dir$") ||
sc.MatchIgnoreCase("!ms$") || sc.chNext == '$') {
sc.SetState(SCE_F_PREPROCESSOR);
} else {
sc.SetState(SCE_F_COMMENT);
}
} else if ((!isFixFormat) && IsADigit(sc.ch) && numNonBlank == 1) {
sc.SetState(SCE_F_LABEL);
} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_F_NUMBER);
} else if ((tolower(sc.ch) == 'b' || tolower(sc.ch) == 'o' ||
tolower(sc.ch) == 'z') && (sc.chNext == '\"' || sc.chNext == '\'')) {
sc.SetState(SCE_F_NUMBER);
sc.Forward();
} else if (sc.ch == '.' && isalpha(sc.chNext)) {
sc.SetState(SCE_F_OPERATOR2);
} else if (IsAWordStart(sc.ch)) {
sc.SetState(SCE_F_IDENTIFIER);
} else if (sc.ch == '\"') {
sc.SetState(SCE_F_STRING2);
} else if (sc.ch == '\'') {
sc.SetState(SCE_F_STRING1);
} else if (isoperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_F_OPERATOR);
}
}
}
sc.Complete();
}
/***************************************/
static void CheckLevelCommentLine(const unsigned int nComL,
Sci_Position nComColB[], Sci_Position nComColF[], Sci_Position &nComCur,
bool comLineB[], bool comLineF[], bool &comLineCur,
int &levelDeltaNext) {
levelDeltaNext = 0;
if (!comLineCur) {
return;
}
if (!comLineF[0] || nComColF[0] != nComCur) {
unsigned int i=0;
for (; i<nComL; i++) {
if (!comLineB[i] || nComColB[i] != nComCur) {
break;
}
}
if (i == nComL) {
levelDeltaNext = -1;
}
}
else if (!comLineB[0] || nComColB[0] != nComCur) {
unsigned int i=0;
for (; i<nComL; i++) {
if (!comLineF[i] || nComColF[i] != nComCur) {
break;
}
}
if (i == nComL) {
levelDeltaNext = 1;
}
}
}
/***************************************/
static void GetIfLineComment(Accessor &styler, bool isFixFormat, const Sci_Position line, bool &isComLine, Sci_Position &comCol) {
Sci_Position col = 0;
isComLine = false;
Sci_Position pos = styler.LineStart(line);
Sci_Position len = styler.Length();
while(pos<len) {
char ch = styler.SafeGetCharAt(pos);
if (ch == '!' || (isFixFormat && col == 0 && (tolower(ch) == 'c' || ch == '*'))) {
isComLine = true;
comCol = col;
break;
}
else if (!IsABlank(ch) || IsALineEnd(ch)) {
break;
}
pos++;
col++;
}
}
/***************************************/
static void StepCommentLine(Accessor &styler, bool isFixFormat, Sci_Position lineCurrent, const unsigned int nComL,
Sci_Position nComColB[], Sci_Position nComColF[], Sci_Position &nComCur,
bool comLineB[], bool comLineF[], bool &comLineCur) {
Sci_Position nLineTotal = styler.GetLine(styler.Length()-1) + 1;
if (lineCurrent >= nLineTotal) {
return;
}
for (int i=nComL-2; i>=0; i--) {
nComColB[i+1] = nComColB[i];
comLineB[i+1] = comLineB[i];
}
nComColB[0] = nComCur;
comLineB[0] = comLineCur;
nComCur = nComColF[0];
comLineCur = comLineF[0];
for (unsigned int i=0; i+1<nComL; i++) {
nComColF[i] = nComColF[i+1];
comLineF[i] = comLineF[i+1];
}
Sci_Position chL = lineCurrent + nComL;
if (chL < nLineTotal) {
GetIfLineComment(styler, isFixFormat, chL, comLineF[nComL-1], nComColF[nComL-1]);
}
else {
comLineF[nComL-1] = false;
}
}
/***************************************/
static void CheckBackComLines(Accessor &styler, bool isFixFormat, Sci_Position lineCurrent, const unsigned int nComL,
Sci_Position nComColB[], Sci_Position nComColF[], Sci_Position nComCur,
bool comLineB[], bool comLineF[], bool &comLineCur) {
unsigned int nLines = nComL + nComL + 1;
bool* comL = new bool[nLines];
Sci_Position* nComCol = new Sci_Position[nLines];
bool comL0;
Sci_Position nComCol0;
GetIfLineComment(styler, isFixFormat, lineCurrent-nComL-1, comL0, nComCol0);
for (unsigned int i=0; i<nComL; i++) {
unsigned copyTo = nComL - i - 1;
comL[copyTo] = comLineB[i];
nComCol[copyTo] = nComColB[i];
}
assert(nComL < nLines);
comL[nComL] = comLineCur;
nComCol[nComL] = nComCur;
for (unsigned int i=0; i<nComL; i++) {
unsigned copyTo = i + nComL + 1;
comL[copyTo] = comLineF[i];
nComCol[copyTo] = nComColF[i];
}
Sci_Position lineC = lineCurrent - nComL + 1;
Sci_PositionU iStart;
if (lineC <= 0) {
lineC = 0;
iStart = nComL - lineCurrent;
}
else {
iStart = 1;
}
bool levChanged = false;
int lev = styler.LevelAt(lineC) & SC_FOLDLEVELNUMBERMASK;
for (Sci_PositionU i=iStart; i<=nComL; i++) {
if (comL[i] && (!comL[i-1] || nComCol[i] != nComCol[i-1])) {
bool increase = true;
Sci_PositionU until = i + nComL;
for (Sci_PositionU j=i+1; j<=until; j++) {
if (!comL[j] || nComCol[j] != nComCol[i]) {
increase = false;
break;
}
}
lev = styler.LevelAt(lineC) & SC_FOLDLEVELNUMBERMASK;
if (increase) {
int levH = lev | SC_FOLDLEVELHEADERFLAG;
lev += 1;
if (levH != styler.LevelAt(lineC)) {
styler.SetLevel(lineC, levH);
}
for (Sci_Position j=lineC+1; j<=lineCurrent; j++) {
if (lev != styler.LevelAt(j)) {
styler.SetLevel(j, lev);
}
}
break;
}
else {
if (lev != styler.LevelAt(lineC)) {
styler.SetLevel(lineC, lev);
}
}
levChanged = true;
}
else if (levChanged && comL[i]) {
if (lev != styler.LevelAt(lineC)) {
styler.SetLevel(lineC, lev);
}
}
lineC++;
}
delete[] comL;
delete[] nComCol;
}
/***************************************/
// To determine the folding level depending on keywords
static int classifyFoldPointFortran(const char* s, const char* prevWord, const char chNextNonBlank) {
int lev = 0;
if ((strcmp(prevWord, "module") == 0 && strcmp(s, "subroutine") == 0)
|| (strcmp(prevWord, "module") == 0 && strcmp(s, "function") == 0)) {
lev = 0;
} else if (strcmp(s, "associate") == 0 || strcmp(s, "block") == 0
|| strcmp(s, "blockdata") == 0 || strcmp(s, "select") == 0
|| strcmp(s, "selecttype") == 0 || strcmp(s, "selectcase") == 0
|| strcmp(s, "do") == 0 || strcmp(s, "enum") ==0
|| strcmp(s, "function") == 0 || strcmp(s, "interface") == 0
|| strcmp(s, "module") == 0 || strcmp(s, "program") == 0
|| strcmp(s, "subroutine") == 0 || strcmp(s, "then") == 0
|| (strcmp(s, "type") == 0 && chNextNonBlank != '(')
|| strcmp(s, "critical") == 0 || strcmp(s, "submodule") == 0){
if (strcmp(prevWord, "end") == 0)
lev = 0;
else
lev = 1;
} else if ((strcmp(s, "end") == 0 && chNextNonBlank != '=')
|| strcmp(s, "endassociate") == 0 || strcmp(s, "endblock") == 0
|| strcmp(s, "endblockdata") == 0 || strcmp(s, "endselect") == 0
|| strcmp(s, "enddo") == 0 || strcmp(s, "endenum") ==0
|| strcmp(s, "endif") == 0 || strcmp(s, "endforall") == 0
|| strcmp(s, "endfunction") == 0 || strcmp(s, "endinterface") == 0
|| strcmp(s, "endmodule") == 0 || strcmp(s, "endprogram") == 0
|| strcmp(s, "endsubroutine") == 0 || strcmp(s, "endtype") == 0
|| strcmp(s, "endwhere") == 0 || strcmp(s, "endcritical") == 0
|| (strcmp(prevWord, "module") == 0 && strcmp(s, "procedure") == 0) // Take care of the "module procedure" statement
|| strcmp(s, "endsubmodule") == 0 || strcmp(s, "endteam") == 0) {
lev = -1;
} else if (strcmp(prevWord, "end") == 0 && strcmp(s, "if") == 0){ // end if
lev = 0;
} else if (strcmp(prevWord, "type") == 0 && strcmp(s, "is") == 0){ // type is
lev = -1;
} else if ((strcmp(prevWord, "end") == 0 && strcmp(s, "procedure") == 0)
|| strcmp(s, "endprocedure") == 0) {
lev = 1; // level back to 0, because no folding support for "module procedure" in submodule
} else if (strcmp(prevWord, "change") == 0 && strcmp(s, "team") == 0){ // change team
lev = 1;
}
return lev;
}
/***************************************/
// Folding the code
static void FoldFortranDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
Accessor &styler, bool isFixFormat) {
bool foldComment = styler.GetPropertyInt("fold.comment", 1) != 0;
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
bool isPrevLine;
if (lineCurrent > 0) {
lineCurrent--;
startPos = styler.LineStart(lineCurrent);
isPrevLine = true;
} else {
isPrevLine = false;
}
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
int style = initStyle;
int levelDeltaNext = 0;
const unsigned int nComL = 3; // defines how many comment lines should be before they are folded
Sci_Position nComColB[nComL] = {};
Sci_Position nComColF[nComL] = {};
Sci_Position nComCur = 0;
bool comLineB[nComL] = {};
bool comLineF[nComL] = {};
bool comLineCur;
Sci_Position nLineTotal = styler.GetLine(styler.Length()-1) + 1;
if (foldComment) {
for (unsigned int i=0; i<nComL; i++) {
Sci_Position chL = lineCurrent-(i+1);
if (chL < 0) {
comLineB[i] = false;
break;
}
GetIfLineComment(styler, isFixFormat, chL, comLineB[i], nComColB[i]);
if (!comLineB[i]) {
for (unsigned int j=i+1; j<nComL; j++) {
comLineB[j] = false;
}
break;
}
}
for (unsigned int i=0; i<nComL; i++) {
Sci_Position chL = lineCurrent+i+1;
if (chL >= nLineTotal) {
comLineF[i] = false;
break;
}
GetIfLineComment(styler, isFixFormat, chL, comLineF[i], nComColF[i]);
}
GetIfLineComment(styler, isFixFormat, lineCurrent, comLineCur, nComCur);
CheckBackComLines(styler, isFixFormat, lineCurrent, nComL, nComColB, nComColF, nComCur,
comLineB, comLineF, comLineCur);
}
int levelCurrent = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
/***************************************/
Sci_Position lastStart = 0;
char prevWord[32] = "";
/***************************************/
for (Sci_PositionU i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
char chNextNonBlank = chNext;
bool nextEOL = false;
if (IsALineEnd(chNextNonBlank)) {
nextEOL = true;
}
Sci_PositionU j=i+1;
while(IsABlank(chNextNonBlank) && j<endPos) {
j ++ ;
chNextNonBlank = styler.SafeGetCharAt(j);
if (IsALineEnd(chNextNonBlank)) {
nextEOL = true;
}
}
if (!nextEOL && j == endPos) {
nextEOL = true;
}
int stylePrev = style;
style = styleNext;
styleNext = styler.StyleAt(i + 1);
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
//
if (((isFixFormat && stylePrev == SCE_F_CONTINUATION) || stylePrev == SCE_F_DEFAULT
|| stylePrev == SCE_F_OPERATOR) && (style == SCE_F_WORD || style == SCE_F_LABEL)) {
// Store last word and label start point.
lastStart = i;
}
/***************************************/
if (style == SCE_F_WORD) {
if(iswordchar(ch) && !iswordchar(chNext)) {
char s[32];
Sci_PositionU k;
for(k=0; (k<31 ) && (k<i-lastStart+1 ); k++) {
s[k] = static_cast<char>(tolower(styler[lastStart+k]));
}
s[k] = '\0';
// Handle the forall and where statement and structure.
if (strcmp(s, "forall") == 0 || (strcmp(s, "where") == 0 && strcmp(prevWord, "else") != 0)) {
if (strcmp(prevWord, "end") != 0) {
j = i + 1;
char chBrace = '(', chSeek = ')', ch1 = styler.SafeGetCharAt(j);
// Find the position of the first (
while (ch1 != chBrace && j<endPos) {
j++;
ch1 = styler.SafeGetCharAt(j);
}
char styBrace = styler.StyleAt(j);
int depth = 1;
char chAtPos;
char styAtPos;
while (j<endPos) {
j++;
chAtPos = styler.SafeGetCharAt(j);
styAtPos = styler.StyleAt(j);
if (styAtPos == styBrace) {
if (chAtPos == chBrace) depth++;
if (chAtPos == chSeek) depth--;
if (depth == 0) break;
}
}
Sci_Position tmpLineCurrent = lineCurrent;
while (j<endPos) {
j++;
chAtPos = styler.SafeGetCharAt(j);
styAtPos = styler.StyleAt(j);
if (!IsALineEnd(chAtPos) && (styAtPos == SCE_F_COMMENT || IsABlank(chAtPos))) continue;
if (isFixFormat) {
if (!IsALineEnd(chAtPos)) {
break;
} else {
if (tmpLineCurrent < styler.GetLine(styler.Length()-1)) {
tmpLineCurrent++;
j = styler.LineStart(tmpLineCurrent);
if (styler.StyleAt(j+5) == SCE_F_CONTINUATION
&& !IsABlank(styler.SafeGetCharAt(j+5)) && styler.SafeGetCharAt(j+5) != '0') {
j += 5;
continue;
} else {
levelDeltaNext++;
break;
}
}
}
} else {
if (chAtPos == '&' && styler.StyleAt(j) == SCE_F_CONTINUATION) {
j = GetContinuedPos(j+1, styler);
continue;
} else if (IsALineEnd(chAtPos)) {
levelDeltaNext++;
break;
} else {
break;
}
}
}
}
} else {
int wordLevelDelta = classifyFoldPointFortran(s, prevWord, chNextNonBlank);
levelDeltaNext += wordLevelDelta;
if (((strcmp(s, "else") == 0) && (nextEOL || chNextNonBlank == '!')) ||
(strcmp(prevWord, "else") == 0 && strcmp(s, "where") == 0) || strcmp(s, "elsewhere") == 0) {
if (!isPrevLine) {
levelCurrent--;
}
levelDeltaNext++;
} else if ((strcmp(prevWord, "else") == 0 && strcmp(s, "if") == 0) || strcmp(s, "elseif") == 0) {
if (!isPrevLine) {
levelCurrent--;
}
} else if ((strcmp(prevWord, "select") == 0 && strcmp(s, "case") == 0) || strcmp(s, "selectcase") == 0 ||
(strcmp(prevWord, "select") == 0 && strcmp(s, "type") == 0) || strcmp(s, "selecttype") == 0) {
levelDeltaNext += 2;
} else if ((strcmp(s, "case") == 0 && chNextNonBlank == '(') || (strcmp(prevWord, "case") == 0 && strcmp(s, "default") == 0) ||
(strcmp(prevWord, "type") == 0 && strcmp(s, "is") == 0) ||
(strcmp(prevWord, "class") == 0 && strcmp(s, "is") == 0) ||
(strcmp(prevWord, "class") == 0 && strcmp(s, "default") == 0) ) {
if (!isPrevLine) {
levelCurrent--;
}
levelDeltaNext++;
} else if ((strcmp(prevWord, "end") == 0 && strcmp(s, "select") == 0) || strcmp(s, "endselect") == 0) {
levelDeltaNext -= 2;
}
// There are multiple forms of "do" loop. The older form with a label "do 100 i=1,10" would require matching
// labels to ensure the folding level does not decrease too far when labels are used for other purposes.
// Since this is difficult, do-label constructs are not folded.
if (strcmp(s, "do") == 0 && IsADigit(chNextNonBlank)) {
// Remove delta for do-label
levelDeltaNext -= wordLevelDelta;
}
}
strcpy(prevWord, s);
}
}
if (atEOL) {
if (foldComment) {
int ldNext;
CheckLevelCommentLine(nComL, nComColB, nComColF, nComCur, comLineB, comLineF, comLineCur, ldNext);
levelDeltaNext += ldNext;
}
int lev = levelCurrent;
if (visibleChars == 0 && foldCompact)
lev |= SC_FOLDLEVELWHITEFLAG;
if ((levelDeltaNext > 0) && (visibleChars > 0))
lev |= SC_FOLDLEVELHEADERFLAG;
if (lev != styler.LevelAt(lineCurrent))
styler.SetLevel(lineCurrent, lev);
lineCurrent++;
levelCurrent += levelDeltaNext;
levelDeltaNext = 0;
visibleChars = 0;
strcpy(prevWord, "");
isPrevLine = false;
if (foldComment) {
StepCommentLine(styler, isFixFormat, lineCurrent, nComL, nComColB, nComColF, nComCur,
comLineB, comLineF, comLineCur);
}
}
/***************************************/
if (!isspacechar(ch)) visibleChars++;
}
/***************************************/
}
/***************************************/
static const char * const FortranWordLists[] = {
"Primary keywords and identifiers",
"Intrinsic functions",
"Extended and user defined functions",
0,
};
/***************************************/
static void ColouriseFortranDocFreeFormat(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
ColouriseFortranDoc(startPos, length, initStyle, keywordlists, styler, false);
}
/***************************************/
static void ColouriseFortranDocFixFormat(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
ColouriseFortranDoc(startPos, length, initStyle, keywordlists, styler, true);
}
/***************************************/
static void FoldFortranDocFreeFormat(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *[], Accessor &styler) {
FoldFortranDoc(startPos, length, initStyle,styler, false);
}
/***************************************/
static void FoldFortranDocFixFormat(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *[], Accessor &styler) {
FoldFortranDoc(startPos, length, initStyle,styler, true);
}
/***************************************/
LexerModule lmFortran(SCLEX_FORTRAN, ColouriseFortranDocFreeFormat, "fortran", FoldFortranDocFreeFormat, FortranWordLists);
LexerModule lmF77(SCLEX_F77, ColouriseFortranDocFixFormat, "f77", FoldFortranDocFixFormat, FortranWordLists);

View File

@ -0,0 +1,267 @@
// Scintilla source code edit control
/** @file LexGAP.cxx
** Lexer for the GAP language. (The GAP System for Computational Discrete Algebra)
** http://www.gap-system.org
**/
// Copyright 2007 by Istvan Szollosi ( szteven <at> gmail <dot> com )
// 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;
static inline bool IsGAPOperator(char ch) {
if (IsASCII(ch) && isalnum(ch)) return false;
if (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 GetRange(Sci_PositionU start, Sci_PositionU end, Accessor &styler, char *s, Sci_PositionU len) {
Sci_PositionU i = 0;
while ((i < end - start + 1) && (i < len-1)) {
s[i] = static_cast<char>(styler[start + i]);
i++;
}
s[i] = '\0';
}
static void ColouriseGAPDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], Accessor &styler) {
WordList &keywords1 = *keywordlists[0];
WordList &keywords2 = *keywordlists[1];
WordList &keywords3 = *keywordlists[2];
WordList &keywords4 = *keywordlists[3];
// Do not leak onto next line
if (initStyle == SCE_GAP_STRINGEOL) initStyle = SCE_GAP_DEFAULT;
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
// Prevent SCE_GAP_STRINGEOL from leaking back to previous line
if ( sc.atLineStart ) {
if (sc.state == SCE_GAP_STRING) sc.SetState(SCE_GAP_STRING);
if (sc.state == SCE_GAP_CHAR) sc.SetState(SCE_GAP_CHAR);
}
// 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
switch (sc.state) {
case SCE_GAP_OPERATOR :
sc.SetState(SCE_GAP_DEFAULT);
break;
case SCE_GAP_NUMBER :
if (!IsADigit(sc.ch)) {
if (sc.ch == '\\') {
if (!sc.atLineEnd) {
if (!IsADigit(sc.chNext)) {
sc.Forward();
sc.ChangeState(SCE_GAP_IDENTIFIER);
}
}
} else if (isalpha(sc.ch) || sc.ch == '_') {
sc.ChangeState(SCE_GAP_IDENTIFIER);
}
else sc.SetState(SCE_GAP_DEFAULT);
}
break;
case SCE_GAP_IDENTIFIER :
if (!(iswordstart(static_cast<char>(sc.ch)) || sc.ch == '$')) {
if (sc.ch == '\\') sc.Forward();
else {
char s[1000];
sc.GetCurrent(s, sizeof(s));
if (keywords1.InList(s)) {
sc.ChangeState(SCE_GAP_KEYWORD);
} else if (keywords2.InList(s)) {
sc.ChangeState(SCE_GAP_KEYWORD2);
} else if (keywords3.InList(s)) {
sc.ChangeState(SCE_GAP_KEYWORD3);
} else if (keywords4.InList(s)) {
sc.ChangeState(SCE_GAP_KEYWORD4);
}
sc.SetState(SCE_GAP_DEFAULT);
}
}
break;
case SCE_GAP_COMMENT :
if (sc.atLineEnd) {
sc.SetState(SCE_GAP_DEFAULT);
}
break;
case SCE_GAP_STRING:
if (sc.atLineEnd) {
sc.ChangeState(SCE_GAP_STRINGEOL);
} else if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_GAP_DEFAULT);
}
break;
case SCE_GAP_CHAR:
if (sc.atLineEnd) {
sc.ChangeState(SCE_GAP_STRINGEOL);
} else if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\'') {
sc.ForwardSetState(SCE_GAP_DEFAULT);
}
break;
case SCE_GAP_STRINGEOL:
if (sc.atLineStart) {
sc.SetState(SCE_GAP_DEFAULT);
}
break;
}
// Determine if a new state should be entered
if (sc.state == SCE_GAP_DEFAULT) {
if (IsGAPOperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_GAP_OPERATOR);
}
else if (IsADigit(sc.ch)) {
sc.SetState(SCE_GAP_NUMBER);
} else if (isalpha(sc.ch) || sc.ch == '_' || sc.ch == '\\' || sc.ch == '$' || sc.ch == '~') {
sc.SetState(SCE_GAP_IDENTIFIER);
if (sc.ch == '\\') sc.Forward();
} else if (sc.ch == '#') {
sc.SetState(SCE_GAP_COMMENT);
} else if (sc.ch == '\"') {
sc.SetState(SCE_GAP_STRING);
} else if (sc.ch == '\'') {
sc.SetState(SCE_GAP_CHAR);
}
}
}
sc.Complete();
}
static int ClassifyFoldPointGAP(const char* s) {
int level = 0;
if (strcmp(s, "function") == 0 ||
strcmp(s, "do") == 0 ||
strcmp(s, "if") == 0 ||
strcmp(s, "repeat") == 0 ) {
level = 1;
} else if (strcmp(s, "end") == 0 ||
strcmp(s, "od") == 0 ||
strcmp(s, "fi") == 0 ||
strcmp(s, "until") == 0 ) {
level = -1;
}
return level;
}
static void FoldGAPDoc( Sci_PositionU startPos, Sci_Position length, int initStyle, WordList** , Accessor &styler) {
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
int style = initStyle;
Sci_Position lastStart = 0;
for (Sci_PositionU 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 (stylePrev != SCE_GAP_KEYWORD && style == SCE_GAP_KEYWORD) {
// Store last word start point.
lastStart = i;
}
if (stylePrev == SCE_GAP_KEYWORD) {
if(iswordchar(ch) && !iswordchar(chNext)) {
char s[100];
GetRange(lastStart, i, styler, s, sizeof(s));
levelCurrent += ClassifyFoldPointGAP(s);
}
}
if (atEOL) {
int lev = levelPrev;
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++;
}
int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}
static const char * const GAPWordListDesc[] = {
"Keywords 1",
"Keywords 2",
"Keywords 3 (unused)",
"Keywords 4 (unused)",
0
};
LexerModule lmGAP(
SCLEX_GAP,
ColouriseGAPDoc,
"gap",
FoldGAPDoc,
GAPWordListDesc);

View File

@ -0,0 +1,772 @@
// Scintilla source code edit control
/** @file LexGDScript.cxx
** Lexer for GDScript.
**/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// Heavily modified later for GDScript
// The License.txt file describes the conditions under which this software may be distributed.
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <string>
#include <string_view>
#include <vector>
#include <map>
#include <algorithm>
#include <functional>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "StringCopy.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "CharacterCategory.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "SubStyles.h"
#include "DefaultLexer.h"
using namespace Scintilla;
using namespace Lexilla;
namespace {
enum kwType { kwOther, kwClass, kwDef, kwExtends};
constexpr int indicatorWhitespace = 1;
bool IsGDStringStart(int ch) {
return (ch == '\'' || ch == '"');
}
bool IsGDComment(Accessor &styler, Sci_Position pos, Sci_Position len) {
return len > 0 && styler[pos] == '#';
}
constexpr bool IsGDSingleQuoteStringState(int st) noexcept {
return ((st == SCE_GD_CHARACTER) || (st == SCE_GD_STRING));
}
constexpr bool IsGDTripleQuoteStringState(int st) noexcept {
return ((st == SCE_GD_TRIPLE) || (st == SCE_GD_TRIPLEDOUBLE));
}
char GetGDStringQuoteChar(int st) noexcept {
if ((st == SCE_GD_CHARACTER) || (st == SCE_GD_TRIPLE))
return '\'';
if ((st == SCE_GD_STRING) || (st == SCE_GD_TRIPLEDOUBLE))
return '"';
return '\0';
}
/* Return the state to use for the string starting at i; *nextIndex will be set to the first index following the quote(s) */
int GetGDStringState(Accessor &styler, Sci_Position i, Sci_PositionU *nextIndex) {
char ch = styler.SafeGetCharAt(i);
char chNext = styler.SafeGetCharAt(i + 1);
if (ch != '"' && ch != '\'') {
*nextIndex = i + 1;
return SCE_GD_DEFAULT;
}
if (ch == chNext && ch == styler.SafeGetCharAt(i + 2)) {
*nextIndex = i + 3;
if (ch == '"')
return SCE_GD_TRIPLEDOUBLE;
else
return SCE_GD_TRIPLE;
} else {
*nextIndex = i + 1;
if (ch == '"')
return SCE_GD_STRING;
else
return SCE_GD_CHARACTER;
}
}
int GetGDStringState(int ch) {
if (ch != '"' && ch != '\'')
return SCE_GD_DEFAULT;
if (ch == '"')
return SCE_GD_STRING;
else
return SCE_GD_CHARACTER;
}
inline bool IsAWordChar(int ch, bool unicodeIdentifiers) {
if (IsASCII(ch))
return (IsAlphaNumeric(ch) || ch == '.' || ch == '_');
if (!unicodeIdentifiers)
return false;
return IsXidContinue(ch);
}
inline bool IsANodePathChar(int ch, bool unicodeIdentifiers) {
if (IsASCII(ch))
return (IsAlphaNumeric(ch) || ch == '_' || ch == '/' || ch =='%');
if (!unicodeIdentifiers)
return false;
return IsXidContinue(ch);
}
inline bool IsAWordStart(int ch, bool unicodeIdentifiers) {
if (IsASCII(ch))
return (IsUpperOrLowerCase(ch) || ch == '_');
if (!unicodeIdentifiers)
return false;
return IsXidStart(ch);
}
bool IsFirstNonWhitespace(Sci_Position pos, Accessor &styler) {
const Sci_Position line = styler.GetLine(pos);
const Sci_Position start_pos = styler.LineStart(line);
for (Sci_Position i = start_pos; i < pos; i++) {
const char ch = styler[i];
if (!(ch == ' ' || ch == '\t'))
return false;
}
return true;
}
// Options used for LexerGDScript
struct OptionsGDScript {
int whingeLevel;
bool base2or8Literals;
bool stringsOverNewline;
bool keywords2NoSubIdentifiers;
bool fold;
bool foldQuotes;
bool foldCompact;
bool unicodeIdentifiers;
OptionsGDScript() noexcept {
whingeLevel = 0;
base2or8Literals = true;
stringsOverNewline = false;
keywords2NoSubIdentifiers = false;
fold = false;
foldQuotes = false;
foldCompact = false;
unicodeIdentifiers = true;
}
};
const char *const gdscriptWordListDesc[] = {
"Keywords",
"Highlighted identifiers",
nullptr
};
struct OptionSetGDScript : public OptionSet<OptionsGDScript> {
OptionSetGDScript() {
DefineProperty("lexer.gdscript.whinge.level", &OptionsGDScript::whingeLevel,
"For GDScript code, checks whether indenting is consistent. "
"The default, 0 turns off indentation checking, "
"1 checks whether each line is potentially inconsistent with the previous line, "
"2 checks whether any space characters occur before a tab character in the indentation, "
"3 checks whether any spaces are in the indentation, and "
"4 checks for any tab characters in the indentation. "
"1 is a good level to use.");
DefineProperty("lexer.gdscript.literals.binary", &OptionsGDScript::base2or8Literals,
"Set to 0 to not recognise binary and octal literals: 0b1011 0o712.");
DefineProperty("lexer.gdscript.strings.over.newline", &OptionsGDScript::stringsOverNewline,
"Set to 1 to allow strings to span newline characters.");
DefineProperty("lexer.gdscript.keywords2.no.sub.identifiers", &OptionsGDScript::keywords2NoSubIdentifiers,
"When enabled, it will not style keywords2 items that are used as a sub-identifier. "
"Example: when set, will not highlight \"foo.open\" when \"open\" is a keywords2 item.");
DefineProperty("fold", &OptionsGDScript::fold);
DefineProperty("fold.gdscript.quotes", &OptionsGDScript::foldQuotes,
"This option enables folding multi-line quoted strings when using the GDScript lexer.");
DefineProperty("fold.compact", &OptionsGDScript::foldCompact);
DefineProperty("lexer.gdscript.unicode.identifiers", &OptionsGDScript::unicodeIdentifiers,
"Set to 0 to not recognise Unicode identifiers.");
DefineWordListSets(gdscriptWordListDesc);
}
};
const char styleSubable[] = { SCE_GD_IDENTIFIER, 0 };
LexicalClass lexicalClasses[] = {
// Lexer GDScript SCLEX_GDSCRIPT SCE_GD_:
0, "SCE_GD_DEFAULT", "default", "White space",
1, "SCE_GD_COMMENTLINE", "comment line", "Comment",
2, "SCE_GD_NUMBER", "literal numeric", "Number",
3, "SCE_GD_STRING", "literal string", "String",
4, "SCE_GD_CHARACTER", "literal string", "Single quoted string",
5, "SCE_GD_WORD", "keyword", "Keyword",
6, "SCE_GD_TRIPLE", "literal string", "Triple quotes",
7, "SCE_GD_TRIPLEDOUBLE", "literal string", "Triple double quotes",
8, "SCE_GD_CLASSNAME", "identifier", "Class name definition",
9, "SCE_GD_FUNCNAME", "identifier", "Function or method name definition",
10, "SCE_GD_OPERATOR", "operator", "Operators",
11, "SCE_GD_IDENTIFIER", "identifier", "Identifiers",
12, "SCE_GD_COMMENTBLOCK", "comment", "Comment-blocks",
13, "SCE_GD_STRINGEOL", "error literal string", "End of line where string is not closed",
14, "SCE_GD_WORD2", "identifier", "Highlighted identifiers",
15, "SCE_GD_ANNOTATION", "annotation", "Annotations",
16, "SCE_GD_NODEPATH", "path", "Node path",
};
}
class LexerGDScript : public DefaultLexer {
WordList keywords;
WordList keywords2;
OptionsGDScript options;
OptionSetGDScript osGDScript;
enum { ssIdentifier };
SubStyles subStyles{styleSubable};
public:
explicit LexerGDScript() :
DefaultLexer("gdscript", SCLEX_GDSCRIPT, lexicalClasses, ELEMENTS(lexicalClasses)) {
}
~LexerGDScript() override {
}
void SCI_METHOD Release() override {
delete this;
}
int SCI_METHOD Version() const override {
return lvRelease5;
}
const char *SCI_METHOD PropertyNames() override {
return osGDScript.PropertyNames();
}
int SCI_METHOD PropertyType(const char *name) override {
return osGDScript.PropertyType(name);
}
const char *SCI_METHOD DescribeProperty(const char *name) override {
return osGDScript.DescribeProperty(name);
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
const char * SCI_METHOD PropertyGet(const char *key) override {
return osGDScript.PropertyGet(key);
}
const char *SCI_METHOD DescribeWordListSets() override {
return osGDScript.DescribeWordListSets();
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void *SCI_METHOD PrivateCall(int, void *) override {
return nullptr;
}
int SCI_METHOD LineEndTypesSupported() override {
return SC_LINE_END_TYPE_UNICODE;
}
int SCI_METHOD AllocateSubStyles(int styleBase, int numberStyles) override {
return subStyles.Allocate(styleBase, numberStyles);
}
int SCI_METHOD SubStylesStart(int styleBase) override {
return subStyles.Start(styleBase);
}
int SCI_METHOD SubStylesLength(int styleBase) override {
return subStyles.Length(styleBase);
}
int SCI_METHOD StyleFromSubStyle(int subStyle) override {
const int styleBase = subStyles.BaseStyle(subStyle);
return styleBase;
}
int SCI_METHOD PrimaryStyleFromStyle(int style) override {
return style;
}
void SCI_METHOD FreeSubStyles() override {
subStyles.Free();
}
void SCI_METHOD SetIdentifiers(int style, const char *identifiers) override {
subStyles.SetIdentifiers(style, identifiers);
}
int SCI_METHOD DistanceToSecondaryStyles() override {
return 0;
}
const char *SCI_METHOD GetSubStyleBases() override {
return styleSubable;
}
static ILexer5 *LexerFactoryGDScript() {
return new LexerGDScript();
}
private:
void ProcessLineEnd(StyleContext &sc, bool &inContinuedString);
};
Sci_Position SCI_METHOD LexerGDScript::PropertySet(const char *key, const char *val) {
if (osGDScript.PropertySet(&options, key, val)) {
return 0;
}
return -1;
}
Sci_Position SCI_METHOD LexerGDScript::WordListSet(int n, const char *wl) {
WordList *wordListN = nullptr;
switch (n) {
case 0:
wordListN = &keywords;
break;
case 1:
wordListN = &keywords2;
break;
default:
break;
}
Sci_Position firstModification = -1;
if (wordListN) {
WordList wlNew;
wlNew.Set(wl);
if (*wordListN != wlNew) {
wordListN->Set(wl);
firstModification = 0;
}
}
return firstModification;
}
void LexerGDScript::ProcessLineEnd(StyleContext &sc, bool &inContinuedString) {
if ((sc.state == SCE_GD_DEFAULT)
|| IsGDTripleQuoteStringState(sc.state)) {
// Perform colourisation of white space and triple quoted strings at end of each line to allow
// tab marking to work inside white space and triple quoted strings
sc.SetState(sc.state);
}
if (IsGDSingleQuoteStringState(sc.state)) {
if (inContinuedString || options.stringsOverNewline) {
inContinuedString = false;
} else {
sc.ChangeState(SCE_GD_STRINGEOL);
sc.ForwardSetState(SCE_GD_DEFAULT);
}
}
}
void SCI_METHOD LexerGDScript::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
Accessor styler(pAccess, nullptr);
const Sci_Position endPos = startPos + length;
// Backtrack to previous line in case need to fix its tab whinging
Sci_Position lineCurrent = styler.GetLine(startPos);
if (startPos > 0) {
if (lineCurrent > 0) {
lineCurrent--;
// Look for backslash-continued lines
while (lineCurrent > 0) {
const Sci_Position eolPos = styler.LineStart(lineCurrent) - 1;
const int eolStyle = styler.StyleAt(eolPos);
if (eolStyle == SCE_GD_STRING || eolStyle == SCE_GD_CHARACTER
|| eolStyle == SCE_GD_STRINGEOL) {
lineCurrent -= 1;
} else {
break;
}
}
startPos = styler.LineStart(lineCurrent);
}
initStyle = startPos == 0 ? SCE_GD_DEFAULT : styler.StyleAt(startPos - 1);
}
initStyle = initStyle & 31;
if (initStyle == SCE_GD_STRINGEOL) {
initStyle = SCE_GD_DEFAULT;
}
kwType kwLast = kwOther;
int spaceFlags = 0;
styler.IndentAmount(lineCurrent, &spaceFlags, IsGDComment);
bool base_n_number = false;
const WordClassifier &classifierIdentifiers = subStyles.Classifier(SCE_GD_IDENTIFIER);
StyleContext sc(startPos, endPos - startPos, initStyle, styler);
bool indentGood = true;
Sci_Position startIndicator = sc.currentPos;
bool inContinuedString = false;
bool percentIsNodePath = false;
int nodePathStringState = SCE_GD_DEFAULT;
for (; sc.More(); sc.Forward()) {
if (sc.atLineStart) {
styler.IndentAmount(lineCurrent, &spaceFlags, IsGDComment);
indentGood = true;
if (options.whingeLevel == 1) {
indentGood = (spaceFlags & wsInconsistent) == 0;
} else if (options.whingeLevel == 2) {
indentGood = (spaceFlags & wsSpaceTab) == 0;
} else if (options.whingeLevel == 3) {
indentGood = (spaceFlags & wsSpace) == 0;
} else if (options.whingeLevel == 4) {
indentGood = (spaceFlags & wsTab) == 0;
}
if (!indentGood) {
styler.IndicatorFill(startIndicator, sc.currentPos, indicatorWhitespace, 0);
startIndicator = sc.currentPos;
}
}
if (sc.atLineEnd) {
percentIsNodePath = false;
ProcessLineEnd(sc, inContinuedString);
lineCurrent++;
if (!sc.More())
break;
}
bool needEOLCheck = false;
if (sc.state == SCE_GD_OPERATOR) {
kwLast = kwOther;
sc.SetState(SCE_GD_DEFAULT);
} else if (sc.state == SCE_GD_NUMBER) {
if (!IsAWordChar(sc.ch, false) &&
!(!base_n_number && ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) {
sc.SetState(SCE_GD_DEFAULT);
}
} else if (sc.state == SCE_GD_IDENTIFIER) {
if ((sc.ch == '.') || (!IsAWordChar(sc.ch, options.unicodeIdentifiers))) {
char s[100];
sc.GetCurrent(s, sizeof(s));
int style = SCE_GD_IDENTIFIER;
if (keywords.InList(s)) {
style = SCE_GD_WORD;
} else if (kwLast == kwClass) {
style = SCE_GD_CLASSNAME;
} else if (kwLast == kwDef) {
style = SCE_GD_FUNCNAME;
} else if (keywords2.InList(s)) {
if (options.keywords2NoSubIdentifiers) {
// We don't want to highlight keywords2
// that are used as a sub-identifier,
// i.e. not open in "foo.open".
const Sci_Position pos = styler.GetStartSegment() - 1;
if (pos < 0 || (styler.SafeGetCharAt(pos, '\0') != '.'))
style = SCE_GD_WORD2;
} else {
style = SCE_GD_WORD2;
}
} else {
const int subStyle = classifierIdentifiers.ValueFor(s);
if (subStyle >= 0) {
style = subStyle;
}
}
sc.ChangeState(style);
sc.SetState(SCE_GD_DEFAULT);
if (style == SCE_GD_WORD) {
if (0 == strcmp(s, "class"))
kwLast = kwClass;
else if (0 == strcmp(s, "func"))
kwLast = kwDef;
else if (0 == strcmp(s, "extends"))
kwLast = kwExtends;
else
kwLast = kwOther;
} else {
kwLast = kwOther;
}
}
} else if ((sc.state == SCE_GD_COMMENTLINE) || (sc.state == SCE_GD_COMMENTBLOCK)) {
if (sc.ch == '\r' || sc.ch == '\n') {
sc.SetState(SCE_GD_DEFAULT);
}
} else if (sc.state == SCE_GD_ANNOTATION) {
if (!IsAWordStart(sc.ch, options.unicodeIdentifiers)) {
sc.SetState(SCE_GD_DEFAULT);
}
} else if (sc.state == SCE_GD_NODEPATH) {
if (nodePathStringState != SCE_GD_DEFAULT) {
if (sc.ch == GetGDStringQuoteChar(nodePathStringState) ) {
nodePathStringState = SCE_GD_DEFAULT;
}
} else {
if (IsGDStringStart(sc.ch)) {
nodePathStringState = GetGDStringState(sc.ch);
} else if (!IsANodePathChar(sc.ch, options.unicodeIdentifiers)) {
sc.SetState(SCE_GD_DEFAULT);
}
}
} else if (IsGDSingleQuoteStringState(sc.state)) {
if (sc.ch == '\\') {
if ((sc.chNext == '\r') && (sc.GetRelative(2) == '\n')) {
sc.Forward();
}
if (sc.chNext == '\n' || sc.chNext == '\r') {
inContinuedString = true;
} else {
// Don't roll over the newline.
sc.Forward();
}
} else if (sc.ch == GetGDStringQuoteChar(sc.state)) {
sc.ForwardSetState(SCE_GD_DEFAULT);
needEOLCheck = true;
}
} else if (sc.state == SCE_GD_TRIPLE) {
if (sc.ch == '\\') {
sc.Forward();
} else if (sc.Match(R"(''')")) {
sc.Forward();
sc.Forward();
sc.ForwardSetState(SCE_GD_DEFAULT);
needEOLCheck = true;
}
} else if (sc.state == SCE_GD_TRIPLEDOUBLE) {
if (sc.ch == '\\') {
sc.Forward();
} else if (sc.Match(R"(""")")) {
sc.Forward();
sc.Forward();
sc.ForwardSetState(SCE_GD_DEFAULT);
needEOLCheck = true;
}
}
if (!indentGood && !IsASpaceOrTab(sc.ch)) {
styler.IndicatorFill(startIndicator, sc.currentPos, indicatorWhitespace, 1);
startIndicator = sc.currentPos;
indentGood = true;
}
// State exit code may have moved on to end of line
if (needEOLCheck && sc.atLineEnd) {
ProcessLineEnd(sc, inContinuedString);
lineCurrent++;
styler.IndentAmount(lineCurrent, &spaceFlags, IsGDComment);
if (!sc.More())
break;
}
// Check for a new state starting character
if (sc.state == SCE_GD_DEFAULT) {
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
if (sc.ch == '0' && (sc.chNext == 'x' || sc.chNext == 'X')) {
base_n_number = true;
sc.SetState(SCE_GD_NUMBER);
} else if (sc.ch == '0' &&
(sc.chNext == 'o' || sc.chNext == 'O' || sc.chNext == 'b' || sc.chNext == 'B')) {
if (options.base2or8Literals) {
base_n_number = true;
sc.SetState(SCE_GD_NUMBER);
} else {
sc.SetState(SCE_GD_NUMBER);
sc.ForwardSetState(SCE_GD_IDENTIFIER);
}
} else {
base_n_number = false;
sc.SetState(SCE_GD_NUMBER);
}
} else if ((sc.ch == '$') || (sc.ch == '%' && (percentIsNodePath || IsFirstNonWhitespace(sc.currentPos, styler)))) {
percentIsNodePath = false;
sc.SetState(SCE_GD_NODEPATH);
} else if (isoperator(sc.ch) || sc.ch == '`') {
percentIsNodePath = !((sc.ch == ')') || (sc.ch == ']') || (sc.ch == '}'));
sc.SetState(SCE_GD_OPERATOR);
} else if (sc.ch == '#') {
sc.SetState(sc.chNext == '#' ? SCE_GD_COMMENTBLOCK : SCE_GD_COMMENTLINE);
} else if (sc.ch == '@') {
if (IsFirstNonWhitespace(sc.currentPos, styler))
sc.SetState(SCE_GD_ANNOTATION);
else
sc.SetState(SCE_GD_OPERATOR);
} else if (IsGDStringStart(sc.ch)) {
Sci_PositionU nextIndex = 0;
sc.SetState(GetGDStringState(styler, sc.currentPos, &nextIndex));
while (nextIndex > (sc.currentPos + 1) && sc.More()) {
sc.Forward();
}
} else if (IsAWordStart(sc.ch, options.unicodeIdentifiers)) {
sc.SetState(SCE_GD_IDENTIFIER);
}
}
}
styler.IndicatorFill(startIndicator, sc.currentPos, indicatorWhitespace, 0);
sc.Complete();
}
static bool IsCommentLine(Sci_Position line, Accessor &styler) {
const Sci_Position pos = styler.LineStart(line);
const Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eol_pos; i++) {
const char ch = styler[i];
if (ch == '#')
return true;
else if (ch != ' ' && ch != '\t')
return false;
}
return false;
}
static bool IsQuoteLine(Sci_Position line, const Accessor &styler) {
const int style = styler.StyleAt(styler.LineStart(line)) & 31;
return IsGDTripleQuoteStringState(style);
}
void SCI_METHOD LexerGDScript::Fold(Sci_PositionU startPos, Sci_Position length, int /*initStyle - unused*/, IDocument *pAccess) {
if (!options.fold)
return;
Accessor styler(pAccess, nullptr);
const Sci_Position maxPos = startPos + length;
const Sci_Position maxLines = (maxPos == styler.Length()) ? styler.GetLine(maxPos) : styler.GetLine(maxPos - 1); // Requested last line
const Sci_Position docLines = styler.GetLine(styler.Length()); // Available last line
// Backtrack to previous non-blank line so we can determine indent level
// for any white space lines (needed esp. within triple quoted strings)
// and so we can fix any preceding fold level (which is why we go back
// at least one line in all cases)
int spaceFlags = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, nullptr);
while (lineCurrent > 0) {
lineCurrent--;
indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, nullptr);
if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG) &&
(!IsCommentLine(lineCurrent, styler)) &&
(!IsQuoteLine(lineCurrent, styler)))
break;
}
int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;
// Set up initial loop state
startPos = styler.LineStart(lineCurrent);
int prev_state = SCE_GD_DEFAULT & 31;
if (lineCurrent >= 1)
prev_state = styler.StyleAt(startPos - 1) & 31;
int prevQuote = options.foldQuotes && IsGDTripleQuoteStringState(prev_state);
// Process all characters to end of requested range or end of any triple quote
//that hangs over the end of the range. Cap processing in all cases
// to end of document (in case of unclosed quote at end).
while ((lineCurrent <= docLines) && ((lineCurrent <= maxLines) || prevQuote)) {
// Gather info
int lev = indentCurrent;
Sci_Position lineNext = lineCurrent + 1;
int indentNext = indentCurrent;
int quote = false;
if (lineNext <= docLines) {
// Information about next line is only available if not at end of document
indentNext = styler.IndentAmount(lineNext, &spaceFlags, nullptr);
const Sci_Position lookAtPos = (styler.LineStart(lineNext) == styler.Length()) ? styler.Length() - 1 : styler.LineStart(lineNext);
const int style = styler.StyleAt(lookAtPos) & 31;
quote = options.foldQuotes && IsGDTripleQuoteStringState(style);
}
const bool quote_start = (quote && !prevQuote);
const bool quote_continue = (quote && prevQuote);
if (!quote || !prevQuote)
indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;
if (quote)
indentNext = indentCurrentLevel;
if (indentNext & SC_FOLDLEVELWHITEFLAG)
indentNext = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel;
if (quote_start) {
// Place fold point at start of triple quoted string
lev |= SC_FOLDLEVELHEADERFLAG;
} else if (quote_continue || prevQuote) {
// Add level to rest of lines in the string
lev = lev + 1;
}
// Skip past any blank lines for next indent level info; we skip also
// comments (all comments, not just those starting in column 0)
// which effectively folds them into surrounding code rather
// than screwing up folding. If comments end file, use the min
// comment indent as the level after
int minCommentLevel = indentCurrentLevel;
while (!quote &&
(lineNext < docLines) &&
((indentNext & SC_FOLDLEVELWHITEFLAG) || (IsCommentLine(lineNext, styler)))) {
if (IsCommentLine(lineNext, styler) && indentNext < minCommentLevel) {
minCommentLevel = indentNext;
}
lineNext++;
indentNext = styler.IndentAmount(lineNext, &spaceFlags, nullptr);
}
const int levelAfterComments = ((lineNext < docLines) ? indentNext & SC_FOLDLEVELNUMBERMASK : minCommentLevel);
const int levelBeforeComments = std::max(indentCurrentLevel, levelAfterComments);
// Now set all the indent levels on the lines we skipped
// Do this from end to start. Once we encounter one line
// which is indented more than the line after the end of
// the comment-block, use the level of the block before
Sci_Position skipLine = lineNext;
int skipLevel = levelAfterComments;
while (--skipLine > lineCurrent) {
const int skipLineIndent = styler.IndentAmount(skipLine, &spaceFlags, nullptr);
if (options.foldCompact) {
if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments)
skipLevel = levelBeforeComments;
const int whiteFlag = skipLineIndent & SC_FOLDLEVELWHITEFLAG;
styler.SetLevel(skipLine, skipLevel | whiteFlag);
} else {
if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments &&
!(skipLineIndent & SC_FOLDLEVELWHITEFLAG) &&
!IsCommentLine(skipLine, styler))
skipLevel = levelBeforeComments;
styler.SetLevel(skipLine, skipLevel);
}
}
// Set fold header on non-quote line
if (!quote && !(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK))
lev |= SC_FOLDLEVELHEADERFLAG;
}
// Keep track of triple quote state of previous line
prevQuote = quote;
// Set fold level for this line and move to next line
styler.SetLevel(lineCurrent, options.foldCompact ? lev : lev & ~SC_FOLDLEVELWHITEFLAG);
indentCurrent = indentNext;
lineCurrent = lineNext;
}
// NOTE: Cannot set level of last line here because indentCurrent doesn't have
// header flag set; the loop above is crafted to take care of this case!
//styler.SetLevel(lineCurrent, indentCurrent);
}
LexerModule lmGDScript(SCLEX_GDSCRIPT, LexerGDScript::LexerFactoryGDScript, "gdscript",
gdscriptWordListDesc);

View File

@ -0,0 +1,315 @@
// Scintilla source code edit control
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// @file LexGui4Cli.cxx
/*
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 scripts/HFacer.py script
3. Run the scripts/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 <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;
#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,
StyleContext *sc, char *buff, Sci_Position length, Sci_Position)
{
Sci_Position 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(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler)
{
styler.StartAt(startPos);
Sci_Position currentline = styler.GetLine(startPos);
int quotestart = 0, oldstate;
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(Sci_PositionU startPos, Sci_Position length, int,
WordList *[], Accessor &styler)
{
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
bool headerPoint = false;
for (Sci_PositionU 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,519 @@
// Scintilla source code edit control
/** @file LexHollywood.cxx
** Lexer for Hollywood
** Written by Andreas Falkenhahn, based on the BlitzBasic/PureBasic/Lua lexers
** Thanks to Nicholai Benalal
** For more information on Hollywood, see http://www.hollywood-mal.com/
** Mail me (andreas <at> airsoftsoftwair <dot> de) for any bugs.
** This code is subject to the same license terms as the rest of the Scintilla project:
** 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 <map>
#include <functional>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "DefaultLexer.h"
using namespace Scintilla;
using namespace Lexilla;
/* Bits:
* 1 - whitespace
* 2 - operator
* 4 - identifier
* 8 - decimal digit
* 16 - hex digit
* 32 - bin digit
* 64 - letter
*/
static int character_classification[128] =
{
0, // NUL ($0)
0, // SOH ($1)
0, // STX ($2)
0, // ETX ($3)
0, // EOT ($4)
0, // ENQ ($5)
0, // ACK ($6)
0, // BEL ($7)
0, // BS ($8)
1, // HT ($9)
1, // LF ($A)
0, // VT ($B)
0, // FF ($C)
1, // CR ($D)
0, // SO ($E)
0, // SI ($F)
0, // DLE ($10)
0, // DC1 ($11)
0, // DC2 ($12)
0, // DC3 ($13)
0, // DC4 ($14)
0, // NAK ($15)
0, // SYN ($16)
0, // ETB ($17)
0, // CAN ($18)
0, // EM ($19)
0, // SUB ($1A)
0, // ESC ($1B)
0, // FS ($1C)
0, // GS ($1D)
0, // RS ($1E)
0, // US ($1F)
1, // space ($20)
4, // ! ($21)
0, // " ($22)
0, // # ($23)
4, // $ ($24)
2, // % ($25)
2, // & ($26)
2, // ' ($27)
2, // ( ($28)
2, // ) ($29)
2, // * ($2A)
2, // + ($2B)
2, // , ($2C)
2, // - ($2D)
// NB: we treat "." as an identifier although it is also an operator and a decimal digit
// the reason why we treat it as an identifier is to support syntax highlighting for
// plugin commands which always use a "." in their names, e.g. pdf.OpenDocument();
// we handle the decimal digit case manually below so that 3.1415 and .123 is styled correctly
// the collateral damage of treating "." as an identifier is that "." is never styled
// SCE_HOLLYWOOD_OPERATOR
4, // . ($2E)
2, // / ($2F)
28, // 0 ($30)
28, // 1 ($31)
28, // 2 ($32)
28, // 3 ($33)
28, // 4 ($34)
28, // 5 ($35)
28, // 6 ($36)
28, // 7 ($37)
28, // 8 ($38)
28, // 9 ($39)
2, // : ($3A)
2, // ; ($3B)
2, // < ($3C)
2, // = ($3D)
2, // > ($3E)
2, // ? ($3F)
0, // @ ($40)
84, // A ($41)
84, // B ($42)
84, // C ($43)
84, // D ($44)
84, // E ($45)
84, // F ($46)
68, // G ($47)
68, // H ($48)
68, // I ($49)
68, // J ($4A)
68, // K ($4B)
68, // L ($4C)
68, // M ($4D)
68, // N ($4E)
68, // O ($4F)
68, // P ($50)
68, // Q ($51)
68, // R ($52)
68, // S ($53)
68, // T ($54)
68, // U ($55)
68, // V ($56)
68, // W ($57)
68, // X ($58)
68, // Y ($59)
68, // Z ($5A)
2, // [ ($5B)
2, // \ ($5C)
2, // ] ($5D)
2, // ^ ($5E)
68, // _ ($5F)
2, // ` ($60)
84, // a ($61)
84, // b ($62)
84, // c ($63)
84, // d ($64)
84, // e ($65)
84, // f ($66)
68, // g ($67)
68, // h ($68)
68, // i ($69)
68, // j ($6A)
68, // k ($6B)
68, // l ($6C)
68, // m ($6D)
68, // n ($6E)
68, // o ($6F)
68, // p ($70)
68, // q ($71)
68, // r ($72)
68, // s ($73)
68, // t ($74)
68, // u ($75)
68, // v ($76)
68, // w ($77)
68, // x ($78)
68, // y ($79)
68, // z ($7A)
2, // { ($7B)
2, // | ($7C)
2, // } ($7D)
2, // ~ ($7E)
0, // &#127; ($7F)
};
static bool IsSpace(int c) {
return c < 128 && (character_classification[c] & 1);
}
static bool IsOperator(int c) {
return c < 128 && (character_classification[c] & 2);
}
static bool IsIdentifier(int c) {
return c < 128 && (character_classification[c] & 4);
}
static bool IsDigit(int c) {
return c < 128 && (character_classification[c] & 8);
}
static bool IsHexDigit(int c) {
return c < 128 && (character_classification[c] & 16);
}
static int LowerCase(int c)
{
if (c >= 'A' && c <= 'Z')
return 'a' + c - 'A';
return c;
}
static int CheckHollywoodFoldPoint(char const *token) {
if (!strcmp(token, "function")) {
return 1;
}
if (!strcmp(token, "endfunction")) {
return -1;
}
return 0;
}
// An individual named option for use in an OptionSet
// Options used for LexerHollywood
struct OptionsHollywood {
bool fold;
bool foldCompact;
OptionsHollywood() {
fold = false;
foldCompact = false;
}
};
static const char * const hollywoodWordListDesc[] = {
"Hollywood keywords",
"Hollywood standard API functions",
"Hollywood plugin API functions",
"Hollywood plugin methods",
0
};
struct OptionSetHollywood : public OptionSet<OptionsHollywood> {
OptionSetHollywood(const char * const wordListDescriptions[]) {
DefineProperty("fold", &OptionsHollywood::fold);
DefineProperty("fold.compact", &OptionsHollywood::foldCompact);
DefineWordListSets(wordListDescriptions);
}
};
class LexerHollywood : public DefaultLexer {
int (*CheckFoldPoint)(char const *);
WordList keywordlists[4];
OptionsHollywood options;
OptionSetHollywood osHollywood;
public:
LexerHollywood(int (*CheckFoldPoint_)(char const *), const char * const wordListDescriptions[]) :
DefaultLexer("hollywood", SCLEX_HOLLYWOOD),
CheckFoldPoint(CheckFoldPoint_),
osHollywood(wordListDescriptions) {
}
virtual ~LexerHollywood() {
}
void SCI_METHOD Release() override {
delete this;
}
int SCI_METHOD Version() const override {
return lvRelease5;
}
const char * SCI_METHOD PropertyNames() override {
return osHollywood.PropertyNames();
}
int SCI_METHOD PropertyType(const char *name) override {
return osHollywood.PropertyType(name);
}
const char * SCI_METHOD DescribeProperty(const char *name) override {
return osHollywood.DescribeProperty(name);
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
const char * SCI_METHOD PropertyGet(const char* key) override {
return osHollywood.PropertyGet(key);
}
const char * SCI_METHOD DescribeWordListSets() override {
return osHollywood.DescribeWordListSets();
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void * SCI_METHOD PrivateCall(int, void *) override {
return 0;
}
static ILexer5 *LexerFactoryHollywood() {
return new LexerHollywood(CheckHollywoodFoldPoint, hollywoodWordListDesc);
}
};
Sci_Position SCI_METHOD LexerHollywood::PropertySet(const char *key, const char *val) {
if (osHollywood.PropertySet(&options, key, val)) {
return 0;
}
return -1;
}
Sci_Position SCI_METHOD LexerHollywood::WordListSet(int n, const char *wl) {
WordList *wordListN = 0;
switch (n) {
case 0:
wordListN = &keywordlists[0];
break;
case 1:
wordListN = &keywordlists[1];
break;
case 2:
wordListN = &keywordlists[2];
break;
case 3:
wordListN = &keywordlists[3];
break;
}
Sci_Position firstModification = -1;
if (wordListN) {
WordList wlNew;
wlNew.Set(wl);
if (*wordListN != wlNew) {
wordListN->Set(wl);
firstModification = 0;
}
}
return firstModification;
}
void SCI_METHOD LexerHollywood::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
LexAccessor styler(pAccess);
styler.StartAt(startPos);
bool inString = false;
StyleContext sc(startPos, length, initStyle, styler);
// Can't use sc.More() here else we miss the last character
for (; ; sc.Forward())
{
if (sc.atLineStart) inString = false;
if (sc.ch == '\"' && sc.chPrev != '\\') inString = !inString;
if (sc.state == SCE_HOLLYWOOD_IDENTIFIER) {
if (!IsIdentifier(sc.ch)) {
char s[100];
int kstates[4] = {
SCE_HOLLYWOOD_KEYWORD,
SCE_HOLLYWOOD_STDAPI,
SCE_HOLLYWOOD_PLUGINAPI,
SCE_HOLLYWOOD_PLUGINMETHOD,
};
sc.GetCurrentLowered(s, sizeof(s));
for (int i = 0; i < 4; i++) {
if (keywordlists[i].InList(s)) {
sc.ChangeState(kstates[i]);
}
}
sc.SetState(SCE_HOLLYWOOD_DEFAULT);
}
} else if (sc.state == SCE_HOLLYWOOD_OPERATOR) {
// always reset to default on operators because otherwise
// comments won't be recognized in sequences like "+/* Hello*/"
// --> "+/*" would be recognized as a sequence of operators
// if (!IsOperator(sc.ch)) sc.SetState(SCE_HOLLYWOOD_DEFAULT);
sc.SetState(SCE_HOLLYWOOD_DEFAULT);
} else if (sc.state == SCE_HOLLYWOOD_PREPROCESSOR) {
if (!IsIdentifier(sc.ch))
sc.SetState(SCE_HOLLYWOOD_DEFAULT);
} else if (sc.state == SCE_HOLLYWOOD_CONSTANT) {
if (!IsIdentifier(sc.ch))
sc.SetState(SCE_HOLLYWOOD_DEFAULT);
} else if (sc.state == SCE_HOLLYWOOD_NUMBER) {
if (!IsDigit(sc.ch) && sc.ch != '.')
sc.SetState(SCE_HOLLYWOOD_DEFAULT);
} else if (sc.state == SCE_HOLLYWOOD_HEXNUMBER) {
if (!IsHexDigit(sc.ch))
sc.SetState(SCE_HOLLYWOOD_DEFAULT);
} else if (sc.state == SCE_HOLLYWOOD_STRING) {
if (sc.ch == '"') {
sc.ForwardSetState(SCE_HOLLYWOOD_DEFAULT);
}
if (sc.atLineEnd) {
sc.SetState(SCE_HOLLYWOOD_DEFAULT);
}
} else if (sc.state == SCE_HOLLYWOOD_COMMENT) {
if (sc.atLineEnd) {
sc.SetState(SCE_HOLLYWOOD_DEFAULT);
}
} else if (sc.state == SCE_HOLLYWOOD_COMMENTBLOCK) {
if (sc.Match("*/") && !inString) {
sc.Forward();
sc.ForwardSetState(SCE_HOLLYWOOD_DEFAULT);
}
} else if (sc.state == SCE_HOLLYWOOD_STRINGBLOCK) {
if (sc.Match("]]") && !inString) {
sc.Forward();
sc.ForwardSetState(SCE_HOLLYWOOD_DEFAULT);
}
}
if (sc.state == SCE_HOLLYWOOD_DEFAULT) {
if (sc.Match(';')) {
sc.SetState(SCE_HOLLYWOOD_COMMENT);
} else if (sc.Match("/*")) {
sc.SetState(SCE_HOLLYWOOD_COMMENTBLOCK);
sc.Forward();
} else if (sc.Match("[[")) {
sc.SetState(SCE_HOLLYWOOD_STRINGBLOCK);
sc.Forward();
} else if (sc.Match('"')) {
sc.SetState(SCE_HOLLYWOOD_STRING);
} else if (sc.Match('$')) {
sc.SetState(SCE_HOLLYWOOD_HEXNUMBER);
} else if (sc.Match("0x") || sc.Match("0X")) { // must be before IsDigit() because of 0x
sc.SetState(SCE_HOLLYWOOD_HEXNUMBER);
sc.Forward();
} else if (sc.ch == '.' && (sc.chNext >= '0' && sc.chNext <= '9')) { // ".1234" style numbers
sc.SetState(SCE_HOLLYWOOD_NUMBER);
sc.Forward();
} else if (IsDigit(sc.ch)) {
sc.SetState(SCE_HOLLYWOOD_NUMBER);
} else if (sc.Match('#')) {
sc.SetState(SCE_HOLLYWOOD_CONSTANT);
} else if (sc.Match('@')) {
sc.SetState(SCE_HOLLYWOOD_PREPROCESSOR);
} else if (IsOperator(sc.ch)) {
sc.SetState(SCE_HOLLYWOOD_OPERATOR);
} else if (IsIdentifier(sc.ch)) {
sc.SetState(SCE_HOLLYWOOD_IDENTIFIER);
}
}
if (!sc.More())
break;
}
sc.Complete();
}
void SCI_METHOD LexerHollywood::Fold(Sci_PositionU startPos, Sci_Position length, int /* initStyle */, IDocument *pAccess) {
if (!options.fold)
return;
LexAccessor styler(pAccess);
Sci_PositionU lengthDoc = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
int done = 0;
char word[256];
int wordlen = 0;
for (Sci_PositionU 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 (!done) {
if (wordlen) { // are we scanning a token already?
word[wordlen] = static_cast<char>(LowerCase(ch));
if (!IsIdentifier(ch)) { // done with token
word[wordlen] = '\0';
levelCurrent += CheckFoldPoint(word);
done = 1;
} else if (wordlen < 255) {
wordlen++;
}
} else { // start scanning at first non-whitespace character
if (!IsSpace(ch)) {
if (style != SCE_HOLLYWOOD_COMMENTBLOCK && IsIdentifier(ch)) {
word[0] = static_cast<char>(LowerCase(ch));
wordlen = 1;
} else // done with this line
done = 1;
}
}
}
if (atEOL) {
int lev = levelPrev;
if (visibleChars == 0 && options.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;
done = 0;
wordlen = 0;
}
if (!IsSpace(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);
}
LexerModule lmHollywood(SCLEX_HOLLYWOOD, LexerHollywood::LexerFactoryHollywood, "hollywood", hollywoodWordListDesc);

View File

@ -0,0 +1,74 @@
// Scintilla source code edit control
/** @file LexIndent.cxx
** Lexer for no language. Used for indentation-based folding of files.
**/
// 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;
static void ColouriseIndentDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[],
Accessor &styler) {
// Indent language means all style bytes are 0 so just mark the end - no need to fill in.
if (length > 0) {
styler.StartAt(startPos + length - 1);
styler.StartSegment(startPos + length - 1);
styler.ColourTo(startPos + length - 1, 0);
}
}
static void FoldIndentDoc(Sci_PositionU startPos, Sci_Position length, int /* initStyle */, WordList *[], Accessor &styler) {
int visibleCharsCurrent, visibleCharsNext;
int levelCurrent, levelNext;
Sci_PositionU i, lineEnd;
Sci_PositionU lengthDoc = startPos + length;
Sci_Position lineCurrent = styler.GetLine(startPos);
i = styler.LineStart(lineCurrent );
lineEnd = styler.LineStart(lineCurrent+1)-1;
if(lineEnd>=lengthDoc) lineEnd = lengthDoc-1;
while(styler[lineEnd]=='\n' || styler[lineEnd]=='\r') lineEnd--;
for(visibleCharsCurrent=0, levelCurrent=SC_FOLDLEVELBASE; !visibleCharsCurrent && i<=lineEnd; i++){
if(isspacechar(styler[i])) levelCurrent++;
else visibleCharsCurrent=1;
}
for(; i<lengthDoc; lineCurrent++) {
i = styler.LineStart(lineCurrent+1);
lineEnd = styler.LineStart(lineCurrent+2)-1;
if(lineEnd>=lengthDoc) lineEnd = lengthDoc-1;
while(styler[lineEnd]=='\n' || styler[lineEnd]=='\r') lineEnd--;
for(visibleCharsNext=0, levelNext=SC_FOLDLEVELBASE; !visibleCharsNext && i<=lineEnd; i++){
if(isspacechar(styler[i])) levelNext++;
else visibleCharsNext=1;
}
int lev = levelCurrent;
if(!visibleCharsCurrent) lev |= SC_FOLDLEVELWHITEFLAG;
else if(levelNext > levelCurrent) lev |= SC_FOLDLEVELHEADERFLAG;
styler.SetLevel(lineCurrent, lev);
levelCurrent = levelNext;
visibleCharsCurrent = visibleCharsNext;
}
}
LexerModule lmIndent(SCLEX_INDENT, ColouriseIndentDoc, "indent", FoldIndentDoc);

View File

@ -0,0 +1,378 @@
// 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.
// Modified by Michael Heath.
// 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;
static bool innoIsBlank(int ch) {
return (ch == ' ') || (ch == '\t');
}
static bool innoNextNotBlankIs(Sci_Position i, Accessor &styler, char needle) {
char ch;
while (i < styler.Length()) {
ch = styler.SafeGetCharAt(i);
if (ch == needle)
return true;
if (!innoIsBlank(ch))
return false;
i++;
}
return false;
}
static void ColouriseInnoDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *keywordLists[], Accessor &styler) {
int state = SCE_INNO_DEFAULT;
char chPrev;
char ch = 0;
char chNext = styler[startPos];
Sci_Position lengthDoc = startPos + length;
char *buffer = new char[length + 1];
Sci_Position bufferCount = 0;
bool isBOL, isEOL, isWS, isBOLWS = 0;
// Save line state later with bitState and bitand with bit... to get line state
int bitState = 0;
int const bitCode = 1, bitMessages = 2, bitCommentCurly = 4, bitCommentRound = 8;
// Get keyword lists
WordList &sectionKeywords = *keywordLists[0];
WordList &standardKeywords = *keywordLists[1];
WordList &parameterKeywords = *keywordLists[2];
WordList &preprocessorKeywords = *keywordLists[3];
WordList &pascalKeywords = *keywordLists[4];
WordList &userKeywords = *keywordLists[5];
// Get line state
Sci_Position curLine = styler.GetLine(startPos);
int curLineState = curLine > 0 ? styler.GetLineState(curLine - 1) : 0;
bool isCode = (curLineState & bitCode);
bool isMessages = (curLineState & bitMessages);
bool isCommentCurly = (curLineState & bitCommentCurly);
bool isCommentRound = (curLineState & bitCommentRound);
bool isCommentSlash = false;
// Continue Pascal multline comment state
if (isCommentCurly || isCommentRound)
state = SCE_INNO_COMMENT_PASCAL;
// Go through all provided text segment
// using the hand-written state machine shown below
styler.StartAt(startPos);
styler.StartSegment(startPos);
for (Sci_Position 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');
if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
// Remember the line state for future incremental lexing
curLine = styler.GetLine(i);
bitState = 0;
if (isCode)
bitState |= bitCode;
if (isMessages)
bitState |= bitMessages;
if (isCommentCurly)
bitState |= bitCommentCurly;
if (isCommentRound)
bitState |= bitCommentRound;
styler.SetLineState(curLine, bitState);
}
switch(state) {
case SCE_INNO_DEFAULT:
if (!isCode && ch == ';' && isBOLWS) {
// Start of a comment
state = SCE_INNO_COMMENT;
styler.ColourTo(i, SCE_INNO_COMMENT);
} else if (ch == '[' && isBOLWS) {
// Start of a section name
state = SCE_INNO_SECTION;
bufferCount = 0;
} else if (ch == '#' && isBOLWS) {
// Start of a preprocessor directive
state = SCE_INNO_PREPROC;
} else if (!isCode && ch == '{' && chNext != '{' && chPrev != '{') {
// Start of an inline expansion
state = SCE_INNO_INLINE_EXPANSION;
} else if (isCode && ch == '{') {
// Start of a Pascal comment
state = SCE_INNO_COMMENT_PASCAL;
isCommentCurly = true;
styler.ColourTo(i, SCE_INNO_COMMENT_PASCAL);
} else if (isCode && (ch == '(' && chNext == '*')) {
// Start of a Pascal comment
state = SCE_INNO_COMMENT_PASCAL;
isCommentRound = true;
styler.ColourTo(i + 1, SCE_INNO_COMMENT_PASCAL);
} else if (isCode && ch == '/' && chNext == '/') {
// Start of C-style comment
state = SCE_INNO_COMMENT_PASCAL;
isCommentSlash = true;
styler.ColourTo(i + 1, SCE_INNO_COMMENT_PASCAL);
} else if (!isMessages && ch == '"') {
// Start of a double-quote string
state = SCE_INNO_STRING_DOUBLE;
styler.ColourTo(i, SCE_INNO_STRING_DOUBLE);
} else if (!isMessages && ch == '\'') {
// Start of a single-quote string
state = SCE_INNO_STRING_SINGLE;
styler.ColourTo(i, SCE_INNO_STRING_SINGLE);
} else if (!isMessages && IsASCII(ch) && (isalpha(ch) || (ch == '_'))) {
// Start of an identifier
state = SCE_INNO_IDENTIFIER;
bufferCount = 0;
buffer[bufferCount++] = static_cast<char>(tolower(ch));
} 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 - 1, SCE_INNO_COMMENT);
styler.ColourTo(i, SCE_INNO_DEFAULT);
} else {
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 (!isCode && standardKeywords.InList(buffer) && innoNextNotBlankIs(i, styler, '=')) {
styler.ColourTo(i - 1, SCE_INNO_KEYWORD);
} else if (!isCode && parameterKeywords.InList(buffer) && innoNextNotBlankIs(i, styler, ':')) {
styler.ColourTo(i - 1, SCE_INNO_PARAMETER);
} else if (isCode && pascalKeywords.InList(buffer)) {
styler.ColourTo(i - 1, SCE_INNO_KEYWORD_PASCAL);
} else if (!isCode && 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);
isCode = !CompareCaseInsensitive(buffer, "code");
isMessages = isCode ? false : (
!CompareCaseInsensitive(buffer, "custommessages")
|| !CompareCaseInsensitive(buffer, "messages"));
} 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 == '"') {
state = SCE_INNO_DEFAULT;
styler.ColourTo(i, SCE_INNO_STRING_DOUBLE);
} else if (isEOL) {
state = SCE_INNO_DEFAULT;
styler.ColourTo(i - 1, SCE_INNO_STRING_DOUBLE);
styler.ColourTo(i, SCE_INNO_DEFAULT);
} else {
styler.ColourTo(i, SCE_INNO_STRING_DOUBLE);
}
break;
case SCE_INNO_STRING_SINGLE:
if (ch == '\'') {
state = SCE_INNO_DEFAULT;
styler.ColourTo(i, SCE_INNO_STRING_SINGLE);
} else if (isEOL) {
state = SCE_INNO_DEFAULT;
styler.ColourTo(i - 1, SCE_INNO_STRING_SINGLE);
styler.ColourTo(i, SCE_INNO_DEFAULT);
} else {
styler.ColourTo(i, SCE_INNO_STRING_SINGLE);
}
break;
case SCE_INNO_INLINE_EXPANSION:
if (ch == '}') {
state = SCE_INNO_DEFAULT;
styler.ColourTo(i, SCE_INNO_INLINE_EXPANSION);
} else if (isEOL) {
state = SCE_INNO_DEFAULT;
styler.ColourTo(i, SCE_INNO_DEFAULT);
}
break;
case SCE_INNO_COMMENT_PASCAL:
if (isCommentSlash) {
if (isEOL) {
state = SCE_INNO_DEFAULT;
isCommentSlash = false;
styler.ColourTo(i - 1, SCE_INNO_COMMENT_PASCAL);
styler.ColourTo(i, SCE_INNO_DEFAULT);
} else {
styler.ColourTo(i, SCE_INNO_COMMENT_PASCAL);
}
} else if (isCommentCurly) {
if (ch == '}') {
state = SCE_INNO_DEFAULT;
isCommentCurly = false;
}
styler.ColourTo(i, SCE_INNO_COMMENT_PASCAL);
} else if (isCommentRound) {
if (ch == ')' && chPrev == '*') {
state = SCE_INNO_DEFAULT;
isCommentRound = false;
}
styler.ColourTo(i, SCE_INNO_COMMENT_PASCAL);
}
break;
}
}
delete []buffer;
}
static const char * const innoWordListDesc[] = {
"Sections",
"Keywords",
"Parameters",
"Preprocessor directives",
"Pascal keywords",
"User defined keywords",
0
};
static void FoldInnoDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
Sci_PositionU endPos = startPos + length;
char chNext = styler[startPos];
Sci_Position lineCurrent = styler.GetLine(startPos);
bool sectionFlag = false;
int levelPrev = lineCurrent > 0 ? styler.LevelAt(lineCurrent - 1) : SC_FOLDLEVELBASE;
int level;
for (Sci_PositionU i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler[i + 1];
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
int style = styler.StyleAt(i);
if (style == SCE_INNO_SECTION)
sectionFlag = true;
if (atEOL || i == endPos - 1) {
if (sectionFlag) {
level = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
if (level == levelPrev)
styler.SetLevel(lineCurrent - 1, levelPrev & ~SC_FOLDLEVELHEADERFLAG);
} else {
level = levelPrev & SC_FOLDLEVELNUMBERMASK;
if (levelPrev & SC_FOLDLEVELHEADERFLAG)
level++;
}
styler.SetLevel(lineCurrent, level);
levelPrev = level;
lineCurrent++;
sectionFlag = false;
}
}
}
LexerModule lmInno(SCLEX_INNOSETUP, ColouriseInnoDoc, "inno", FoldInnoDoc, innoWordListDesc);

View File

@ -0,0 +1,503 @@
// Scintilla source code edit control
/**
* @file LexJSON.cxx
* @date February 19, 2016
* @brief Lexer for JSON and JSON-LD formats
* @author nkmathew
*
* The License.txt file describes the conditions under which this software may
* be distributed.
*
*/
#include <cstdlib>
#include <cassert>
#include <cctype>
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
#include <map>
#include <functional>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "DefaultLexer.h"
using namespace Scintilla;
using namespace Lexilla;
static const char *const JSONWordListDesc[] = {
"JSON Keywords",
"JSON-LD Keywords",
0
};
/**
* Used to detect compact IRI/URLs in JSON-LD without first looking ahead for the
* colon separating the prefix and suffix
*
* https://www.w3.org/TR/json-ld/#dfn-compact-iri
*/
struct CompactIRI {
int colonCount;
bool foundInvalidChar;
CharacterSet setCompactIRI;
CompactIRI() {
colonCount = 0;
foundInvalidChar = false;
setCompactIRI = CharacterSet(CharacterSet::setAlpha, "$_-");
}
void resetState() {
colonCount = 0;
foundInvalidChar = false;
}
void checkChar(int ch) {
if (ch == ':') {
colonCount++;
} else {
foundInvalidChar |= !setCompactIRI.Contains(ch);
}
}
bool shouldHighlight() const {
return !foundInvalidChar && colonCount == 1;
}
};
/**
* Keeps track of escaped characters in strings as per:
*
* https://tools.ietf.org/html/rfc7159#section-7
*/
struct EscapeSequence {
int digitsLeft;
CharacterSet setHexDigits;
CharacterSet setEscapeChars;
EscapeSequence() {
digitsLeft = 0;
setHexDigits = CharacterSet(CharacterSet::setDigits, "ABCDEFabcdef");
setEscapeChars = CharacterSet(CharacterSet::setNone, "\\\"tnbfru/");
}
// Returns true if the following character is a valid escaped character
bool newSequence(int nextChar) {
digitsLeft = 0;
if (nextChar == 'u') {
digitsLeft = 5;
} else if (!setEscapeChars.Contains(nextChar)) {
return false;
}
return true;
}
bool atEscapeEnd() const {
return digitsLeft <= 0;
}
bool isInvalidChar(int currChar) const {
return !setHexDigits.Contains(currChar);
}
};
struct OptionsJSON {
bool foldCompact;
bool fold;
bool allowComments;
bool escapeSequence;
OptionsJSON() {
foldCompact = false;
fold = false;
allowComments = false;
escapeSequence = false;
}
};
struct OptionSetJSON : public OptionSet<OptionsJSON> {
OptionSetJSON() {
DefineProperty("lexer.json.escape.sequence", &OptionsJSON::escapeSequence,
"Set to 1 to enable highlighting of escape sequences in strings");
DefineProperty("lexer.json.allow.comments", &OptionsJSON::allowComments,
"Set to 1 to enable highlighting of line/block comments in JSON");
DefineProperty("fold.compact", &OptionsJSON::foldCompact);
DefineProperty("fold", &OptionsJSON::fold);
DefineWordListSets(JSONWordListDesc);
}
};
class LexerJSON : public DefaultLexer {
OptionsJSON options;
OptionSetJSON optSetJSON;
EscapeSequence escapeSeq;
WordList keywordsJSON;
WordList keywordsJSONLD;
CharacterSet setOperators;
CharacterSet setURL;
CharacterSet setKeywordJSONLD;
CharacterSet setKeywordJSON;
CompactIRI compactIRI;
static bool IsNextNonWhitespace(LexAccessor &styler, Sci_Position start, char ch) {
Sci_Position i = 0;
while (i < 50) {
i++;
char curr = styler.SafeGetCharAt(start+i, '\0');
char next = styler.SafeGetCharAt(start+i+1, '\0');
bool atEOL = (curr == '\r' && next != '\n') || (curr == '\n');
if (curr == ch) {
return true;
} else if (!isspacechar(curr) || atEOL) {
return false;
}
}
return false;
}
/**
* Looks for the colon following the end quote
*
* Assumes property names of lengths no longer than a 100 characters.
* The colon is also expected to be less than 50 spaces after the end
* quote for the string to be considered a property name
*/
static bool AtPropertyName(LexAccessor &styler, Sci_Position start) {
Sci_Position i = 0;
bool escaped = false;
while (i < 100) {
i++;
char curr = styler.SafeGetCharAt(start+i, '\0');
if (escaped) {
escaped = false;
continue;
}
escaped = curr == '\\';
if (curr == '"') {
return IsNextNonWhitespace(styler, start+i, ':');
} else if (!curr) {
return false;
}
}
return false;
}
static bool IsNextWordInList(WordList &keywordList, CharacterSet wordSet,
StyleContext &context, LexAccessor &styler) {
char word[51];
Sci_Position currPos = (Sci_Position) context.currentPos;
int i = 0;
while (i < 50) {
char ch = styler.SafeGetCharAt(currPos + i);
if (!wordSet.Contains(ch)) {
break;
}
word[i] = ch;
i++;
}
word[i] = '\0';
return keywordList.InList(word);
}
public:
LexerJSON() :
DefaultLexer("json", SCLEX_JSON),
setOperators(CharacterSet::setNone, "[{}]:,"),
setURL(CharacterSet::setAlphaNum, "-._~:/?#[]@!$&'()*+,),="),
setKeywordJSONLD(CharacterSet::setAlpha, ":@"),
setKeywordJSON(CharacterSet::setAlpha, "$_") {
}
virtual ~LexerJSON() {}
int SCI_METHOD Version() const override {
return lvRelease5;
}
void SCI_METHOD Release() override {
delete this;
}
const char *SCI_METHOD PropertyNames() override {
return optSetJSON.PropertyNames();
}
int SCI_METHOD PropertyType(const char *name) override {
return optSetJSON.PropertyType(name);
}
const char *SCI_METHOD DescribeProperty(const char *name) override {
return optSetJSON.DescribeProperty(name);
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override {
if (optSetJSON.PropertySet(&options, key, val)) {
return 0;
}
return -1;
}
const char * SCI_METHOD PropertyGet(const char *key) override {
return optSetJSON.PropertyGet(key);
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override {
WordList *wordListN = 0;
switch (n) {
case 0:
wordListN = &keywordsJSON;
break;
case 1:
wordListN = &keywordsJSONLD;
break;
}
Sci_Position firstModification = -1;
if (wordListN) {
if (wordListN->Set(wl)) {
firstModification = 0;
}
}
return firstModification;
}
void *SCI_METHOD PrivateCall(int, void *) override {
return 0;
}
static ILexer5 *LexerFactoryJSON() {
return new LexerJSON;
}
const char *SCI_METHOD DescribeWordListSets() override {
return optSetJSON.DescribeWordListSets();
}
void SCI_METHOD Lex(Sci_PositionU startPos,
Sci_Position length,
int initStyle,
IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos,
Sci_Position length,
int initStyle,
IDocument *pAccess) override;
};
void SCI_METHOD LexerJSON::Lex(Sci_PositionU startPos,
Sci_Position length,
int initStyle,
IDocument *pAccess) {
LexAccessor styler(pAccess);
StyleContext context(startPos, length, initStyle, styler);
int stringStyleBefore = SCE_JSON_STRING;
while (context.More()) {
switch (context.state) {
case SCE_JSON_BLOCKCOMMENT:
if (context.Match("*/")) {
context.Forward();
context.ForwardSetState(SCE_JSON_DEFAULT);
}
break;
case SCE_JSON_LINECOMMENT:
if (context.MatchLineEnd()) {
context.SetState(SCE_JSON_DEFAULT);
}
break;
case SCE_JSON_STRINGEOL:
if (context.atLineStart) {
context.SetState(SCE_JSON_DEFAULT);
}
break;
case SCE_JSON_ESCAPESEQUENCE:
escapeSeq.digitsLeft--;
if (!escapeSeq.atEscapeEnd()) {
if (escapeSeq.isInvalidChar(context.ch)) {
context.SetState(SCE_JSON_ERROR);
}
break;
}
if (context.ch == '"') {
context.SetState(stringStyleBefore);
context.ForwardSetState(SCE_JSON_DEFAULT);
} else if (context.ch == '\\') {
if (!escapeSeq.newSequence(context.chNext)) {
context.SetState(SCE_JSON_ERROR);
}
context.Forward();
} else {
context.SetState(stringStyleBefore);
if (context.atLineEnd) {
context.ChangeState(SCE_JSON_STRINGEOL);
}
}
break;
case SCE_JSON_PROPERTYNAME:
case SCE_JSON_STRING:
if (context.ch == '"') {
if (compactIRI.shouldHighlight()) {
context.ChangeState(SCE_JSON_COMPACTIRI);
context.ForwardSetState(SCE_JSON_DEFAULT);
compactIRI.resetState();
} else {
context.ForwardSetState(SCE_JSON_DEFAULT);
}
} else if (context.atLineEnd) {
context.ChangeState(SCE_JSON_STRINGEOL);
} else if (context.ch == '\\') {
stringStyleBefore = context.state;
if (options.escapeSequence) {
context.SetState(SCE_JSON_ESCAPESEQUENCE);
if (!escapeSeq.newSequence(context.chNext)) {
context.SetState(SCE_JSON_ERROR);
}
}
context.Forward();
} else if (context.Match("https://") ||
context.Match("http://") ||
context.Match("ssh://") ||
context.Match("git://") ||
context.Match("svn://") ||
context.Match("ftp://") ||
context.Match("mailto:")) {
// Handle most common URI schemes only
stringStyleBefore = context.state;
context.SetState(SCE_JSON_URI);
} else if (context.ch == '@') {
// https://www.w3.org/TR/json-ld/#dfn-keyword
if (IsNextWordInList(keywordsJSONLD, setKeywordJSONLD, context, styler)) {
stringStyleBefore = context.state;
context.SetState(SCE_JSON_LDKEYWORD);
}
} else {
compactIRI.checkChar(context.ch);
}
break;
case SCE_JSON_LDKEYWORD:
case SCE_JSON_URI:
if ((!setKeywordJSONLD.Contains(context.ch) &&
(context.state == SCE_JSON_LDKEYWORD)) ||
(!setURL.Contains(context.ch))) {
context.SetState(stringStyleBefore);
}
if (context.ch == '"') {
context.ForwardSetState(SCE_JSON_DEFAULT);
} else if (context.atLineEnd) {
context.ChangeState(SCE_JSON_STRINGEOL);
}
break;
case SCE_JSON_OPERATOR:
case SCE_JSON_NUMBER:
context.SetState(SCE_JSON_DEFAULT);
break;
case SCE_JSON_ERROR:
if (context.MatchLineEnd()) {
context.SetState(SCE_JSON_DEFAULT);
}
break;
case SCE_JSON_KEYWORD:
if (!setKeywordJSON.Contains(context.ch)) {
context.SetState(SCE_JSON_DEFAULT);
}
break;
}
if (context.state == SCE_JSON_DEFAULT) {
if (context.ch == '"') {
compactIRI.resetState();
context.SetState(SCE_JSON_STRING);
Sci_Position currPos = static_cast<Sci_Position>(context.currentPos);
if (AtPropertyName(styler, currPos)) {
context.SetState(SCE_JSON_PROPERTYNAME);
}
} else if (setOperators.Contains(context.ch)) {
context.SetState(SCE_JSON_OPERATOR);
} else if (options.allowComments && context.Match("/*")) {
context.SetState(SCE_JSON_BLOCKCOMMENT);
context.Forward();
} else if (options.allowComments && context.Match("//")) {
context.SetState(SCE_JSON_LINECOMMENT);
} else if (setKeywordJSON.Contains(context.ch)) {
if (IsNextWordInList(keywordsJSON, setKeywordJSON, context, styler)) {
context.SetState(SCE_JSON_KEYWORD);
}
}
bool numberStart =
IsADigit(context.ch) && (context.chPrev == '+'||
context.chPrev == '-' ||
context.atLineStart ||
IsASpace(context.chPrev) ||
setOperators.Contains(context.chPrev));
bool exponentPart =
tolower(context.ch) == 'e' &&
IsADigit(context.chPrev) &&
(IsADigit(context.chNext) ||
context.chNext == '+' ||
context.chNext == '-');
bool signPart =
(context.ch == '-' || context.ch == '+') &&
((tolower(context.chPrev) == 'e' && IsADigit(context.chNext)) ||
((IsASpace(context.chPrev) || setOperators.Contains(context.chPrev))
&& IsADigit(context.chNext)));
bool adjacentDigit =
IsADigit(context.ch) && IsADigit(context.chPrev);
bool afterExponent = IsADigit(context.ch) && tolower(context.chPrev) == 'e';
bool dotPart = context.ch == '.' &&
IsADigit(context.chPrev) &&
IsADigit(context.chNext);
bool afterDot = IsADigit(context.ch) && context.chPrev == '.';
if (numberStart ||
exponentPart ||
signPart ||
adjacentDigit ||
dotPart ||
afterExponent ||
afterDot) {
context.SetState(SCE_JSON_NUMBER);
} else if (context.state == SCE_JSON_DEFAULT && !IsASpace(context.ch)) {
context.SetState(SCE_JSON_ERROR);
}
}
context.Forward();
}
context.Complete();
}
void SCI_METHOD LexerJSON::Fold(Sci_PositionU startPos,
Sci_Position length,
int,
IDocument *pAccess) {
if (!options.fold) {
return;
}
LexAccessor styler(pAccess);
Sci_PositionU currLine = styler.GetLine(startPos);
Sci_PositionU endPos = startPos + length;
int currLevel = SC_FOLDLEVELBASE;
if (currLine > 0)
currLevel = styler.LevelAt(currLine - 1) >> 16;
int nextLevel = currLevel;
int visibleChars = 0;
for (Sci_PositionU i = startPos; i < endPos; i++) {
char curr = styler.SafeGetCharAt(i);
char next = styler.SafeGetCharAt(i+1);
bool atEOL = (curr == '\r' && next != '\n') || (curr == '\n');
if (styler.StyleAt(i) == SCE_JSON_OPERATOR) {
if (curr == '{' || curr == '[') {
nextLevel++;
} else if (curr == '}' || curr == ']') {
nextLevel--;
}
}
if (atEOL || i == (endPos-1)) {
int level = currLevel | nextLevel << 16;
if (!visibleChars && options.foldCompact) {
level |= SC_FOLDLEVELWHITEFLAG;
} else if (nextLevel > currLevel) {
level |= SC_FOLDLEVELHEADERFLAG;
}
if (level != styler.LevelAt(currLine)) {
styler.SetLevel(currLine, level);
}
currLine++;
currLevel = nextLevel;
visibleChars = 0;
}
if (!isspacechar(curr)) {
visibleChars++;
}
}
}
LexerModule lmJSON(SCLEX_JSON,
LexerJSON::LexerFactoryJSON,
"json",
JSONWordListDesc);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,474 @@
// 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);

View File

@ -0,0 +1,137 @@
// Scintilla source code edit control
/** @file LexKix.cxx
** Lexer for KIX-Scripts.
**/
// Copyright 2004 by Manfred Becker <manfred@becker-trdf.de>
// The License.txt file describes the conditions under which this software may be distributed.
// Edited by Lee Wilmott (24-Jun-2014) added support for block comments
#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;
// Extended to accept accented characters
static inline bool IsAWordChar(int ch) {
return ch >= 0x80 || isalnum(ch) || ch == '_';
}
static inline bool IsOperator(const int ch) {
return (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '&' || ch == '|' || ch == '<' || ch == '>' || ch == '=');
}
static void ColouriseKixDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler) {
WordList &keywords = *keywordlists[0];
WordList &keywords2 = *keywordlists[1];
WordList &keywords3 = *keywordlists[2];
// WordList &keywords4 = *keywordlists[3];
styler.StartAt(startPos);
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
if (sc.state == SCE_KIX_COMMENT) {
if (sc.atLineEnd) {
sc.SetState(SCE_KIX_DEFAULT);
}
} else if (sc.state == SCE_KIX_COMMENTSTREAM) {
if (sc.ch == '/' && sc.chPrev == '*') {
sc.ForwardSetState(SCE_KIX_DEFAULT);
}
} else if (sc.state == SCE_KIX_STRING1) {
// This is a doubles quotes string
if (sc.ch == '\"') {
sc.ForwardSetState(SCE_KIX_DEFAULT);
}
} else if (sc.state == SCE_KIX_STRING2) {
// This is a single quote string
if (sc.ch == '\'') {
sc.ForwardSetState(SCE_KIX_DEFAULT);
}
} else if (sc.state == SCE_KIX_NUMBER) {
if (!IsADigit(sc.ch)) {
sc.SetState(SCE_KIX_DEFAULT);
}
} else if (sc.state == SCE_KIX_VAR) {
if (!IsAWordChar(sc.ch)) {
sc.SetState(SCE_KIX_DEFAULT);
}
} else if (sc.state == SCE_KIX_MACRO) {
if (!IsAWordChar(sc.ch) && !IsADigit(sc.ch)) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
if (!keywords3.InList(&s[1])) {
sc.ChangeState(SCE_KIX_DEFAULT);
}
sc.SetState(SCE_KIX_DEFAULT);
}
} else if (sc.state == SCE_KIX_OPERATOR) {
if (!IsOperator(sc.ch)) {
sc.SetState(SCE_KIX_DEFAULT);
}
} else if (sc.state == SCE_KIX_IDENTIFIER) {
if (!IsAWordChar(sc.ch)) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
if (keywords.InList(s)) {
sc.ChangeState(SCE_KIX_KEYWORD);
} else if (keywords2.InList(s)) {
sc.ChangeState(SCE_KIX_FUNCTIONS);
}
sc.SetState(SCE_KIX_DEFAULT);
}
}
// Determine if a new state should be entered.
if (sc.state == SCE_KIX_DEFAULT) {
if (sc.ch == ';') {
sc.SetState(SCE_KIX_COMMENT);
} else if (sc.ch == '/' && sc.chNext == '*') {
sc.SetState(SCE_KIX_COMMENTSTREAM);
} else if (sc.ch == '\"') {
sc.SetState(SCE_KIX_STRING1);
} else if (sc.ch == '\'') {
sc.SetState(SCE_KIX_STRING2);
} else if (sc.ch == '$') {
sc.SetState(SCE_KIX_VAR);
} else if (sc.ch == '@') {
sc.SetState(SCE_KIX_MACRO);
} else if (IsADigit(sc.ch) || ((sc.ch == '.' || sc.ch == '&') && IsADigit(sc.chNext))) {
sc.SetState(SCE_KIX_NUMBER);
} else if (IsOperator(sc.ch)) {
sc.SetState(SCE_KIX_OPERATOR);
} else if (IsAWordChar(sc.ch)) {
sc.SetState(SCE_KIX_IDENTIFIER);
}
}
}
sc.Complete();
}
LexerModule lmKix(SCLEX_KIX, ColouriseKixDoc, "kix");

View File

@ -0,0 +1,563 @@
// Scintilla source code edit control
/** @file LexLaTeX.cxx
** Lexer for LaTeX2e.
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
// Modified by G. HU in 2013. Added folding, syntax highting inside math environments, and changed some minor behaviors.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include <string>
#include <string_view>
#include <vector>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "PropSetSimple.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "DefaultLexer.h"
#include "LexerBase.h"
using namespace Scintilla;
using namespace Lexilla;
using namespace std;
struct latexFoldSave {
latexFoldSave() : structLev(0) {
for (int i = 0; i < 8; ++i) openBegins[i] = 0;
}
latexFoldSave(const latexFoldSave &save) : structLev(save.structLev) {
for (int i = 0; i < 8; ++i) openBegins[i] = save.openBegins[i];
}
latexFoldSave &operator=(const latexFoldSave &save) {
if (this != &save) {
structLev = save.structLev;
for (int i = 0; i < 8; ++i) openBegins[i] = save.openBegins[i];
}
return *this;
}
int openBegins[8];
Sci_Position structLev;
};
class LexerLaTeX : public LexerBase {
private:
vector<int> modes;
void setMode(Sci_Position line, int mode) {
if (line >= static_cast<Sci_Position>(modes.size())) modes.resize(line + 1, 0);
modes[line] = mode;
}
int getMode(Sci_Position line) {
if (line >= 0 && line < static_cast<Sci_Position>(modes.size())) return modes[line];
return 0;
}
void truncModes(Sci_Position numLines) {
if (static_cast<Sci_Position>(modes.size()) > numLines * 2 + 256)
modes.resize(numLines + 128);
}
vector<latexFoldSave> saves;
void setSave(Sci_Position line, const latexFoldSave &save) {
if (line >= static_cast<Sci_Position>(saves.size())) saves.resize(line + 1);
saves[line] = save;
}
void getSave(Sci_Position line, latexFoldSave &save) {
if (line >= 0 && line < static_cast<Sci_Position>(saves.size())) save = saves[line];
else {
save.structLev = 0;
for (int i = 0; i < 8; ++i) save.openBegins[i] = 0;
}
}
void truncSaves(Sci_Position numLines) {
if (static_cast<Sci_Position>(saves.size()) > numLines * 2 + 256)
saves.resize(numLines + 128);
}
public:
static ILexer5 *LexerFactoryLaTeX() {
return new LexerLaTeX();
}
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
// ILexer5 methods
const char * SCI_METHOD GetName() override {
return "latex";
}
int SCI_METHOD GetIdentifier() override {
return SCLEX_LATEX;
}
};
static bool latexIsSpecial(int ch) {
return (ch == '#') || (ch == '$') || (ch == '%') || (ch == '&') || (ch == '_') ||
(ch == '{') || (ch == '}') || (ch == ' ');
}
static bool latexIsBlank(int ch) {
return (ch == ' ') || (ch == '\t');
}
static bool latexIsBlankAndNL(int ch) {
return (ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n');
}
static bool latexIsLetter(int ch) {
return IsASCII(ch) && isalpha(ch);
}
static bool latexIsTagValid(Sci_Position &i, Sci_Position l, Accessor &styler) {
while (i < l) {
if (styler.SafeGetCharAt(i) == '{') {
while (i < l) {
i++;
if (styler.SafeGetCharAt(i) == '}') {
return true;
} else if (!latexIsLetter(styler.SafeGetCharAt(i)) &&
styler.SafeGetCharAt(i)!='*') {
return false;
}
}
} else if (!latexIsBlank(styler.SafeGetCharAt(i))) {
return false;
}
i++;
}
return false;
}
static bool latexNextNotBlankIs(Sci_Position i, Accessor &styler, char needle) {
char ch;
while (i < styler.Length()) {
ch = styler.SafeGetCharAt(i);
if (!latexIsBlankAndNL(ch) && ch != '*') {
if (ch == needle)
return true;
else
return false;
}
i++;
}
return false;
}
static bool latexLastWordIs(Sci_Position start, Accessor &styler, const char *needle) {
Sci_PositionU i = 0;
Sci_PositionU l = static_cast<Sci_PositionU>(strlen(needle));
Sci_Position ini = start-l+1;
char s[32];
while (i < l && i < 31) {
s[i] = styler.SafeGetCharAt(ini + i);
i++;
}
s[i] = '\0';
return (strcmp(s, needle) == 0);
}
static bool latexLastWordIsMathEnv(Sci_Position pos, Accessor &styler) {
Sci_Position i, j;
char s[32];
const char *mathEnvs[] = { "align", "alignat", "flalign", "gather",
"multiline", "displaymath", "eqnarray", "equation" };
if (styler.SafeGetCharAt(pos) != '}') return false;
for (i = pos - 1; i >= 0; --i) {
if (styler.SafeGetCharAt(i) == '{') break;
if (pos - i >= 20) return false;
}
if (i < 0 || i == pos - 1) return false;
++i;
for (j = 0; i + j < pos; ++j)
s[j] = styler.SafeGetCharAt(i + j);
s[j] = '\0';
if (j == 0) return false;
if (s[j - 1] == '*') s[--j] = '\0';
for (i = 0; i < static_cast<int>(sizeof(mathEnvs) / sizeof(const char *)); ++i)
if (strcmp(s, mathEnvs[i]) == 0) return true;
return false;
}
static inline void latexStateReset(int &mode, int &state) {
switch (mode) {
case 1: state = SCE_L_MATH; break;
case 2: state = SCE_L_MATH2; break;
default: state = SCE_L_DEFAULT; break;
}
}
// There are cases not handled correctly, like $abcd\textrm{what is $x+y$}z+w$.
// But I think it's already good enough.
void SCI_METHOD LexerLaTeX::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
// startPos is assumed to be the first character of a line
Accessor styler(pAccess, &props);
styler.StartAt(startPos);
int mode = getMode(styler.GetLine(startPos) - 1);
int state = initStyle;
if (state == SCE_L_ERROR || state == SCE_L_SHORTCMD || state == SCE_L_SPECIAL) // should not happen
latexStateReset(mode, state);
char chNext = styler.SafeGetCharAt(startPos);
char chVerbatimDelim = '\0';
styler.StartSegment(startPos);
Sci_Position lengthDoc = startPos + length;
for (Sci_Position i = startPos; i < lengthDoc; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if (styler.IsLeadByte(ch)) {
i++;
chNext = styler.SafeGetCharAt(i + 1);
continue;
}
if (ch == '\r' || ch == '\n')
setMode(styler.GetLine(i), mode);
switch (state) {
case SCE_L_DEFAULT :
switch (ch) {
case '\\' :
styler.ColourTo(i - 1, state);
if (latexIsLetter(chNext)) {
state = SCE_L_COMMAND;
} else if (latexIsSpecial(chNext)) {
styler.ColourTo(i + 1, SCE_L_SPECIAL);
i++;
chNext = styler.SafeGetCharAt(i + 1);
} else if (chNext == '\r' || chNext == '\n') {
styler.ColourTo(i, SCE_L_ERROR);
} else if (IsASCII(chNext)) {
styler.ColourTo(i + 1, SCE_L_SHORTCMD);
if (chNext == '(') {
mode = 1;
state = SCE_L_MATH;
} else if (chNext == '[') {
mode = 2;
state = SCE_L_MATH2;
}
i++;
chNext = styler.SafeGetCharAt(i + 1);
}
break;
case '$' :
styler.ColourTo(i - 1, state);
if (chNext == '$') {
styler.ColourTo(i + 1, SCE_L_SHORTCMD);
mode = 2;
state = SCE_L_MATH2;
i++;
chNext = styler.SafeGetCharAt(i + 1);
} else {
styler.ColourTo(i, SCE_L_SHORTCMD);
mode = 1;
state = SCE_L_MATH;
}
break;
case '%' :
styler.ColourTo(i - 1, state);
state = SCE_L_COMMENT;
break;
}
break;
// These 3 will never be reached.
case SCE_L_ERROR:
case SCE_L_SPECIAL:
case SCE_L_SHORTCMD:
break;
case SCE_L_COMMAND :
if (!latexIsLetter(chNext)) {
styler.ColourTo(i, state);
if (latexNextNotBlankIs(i + 1, styler, '[' )) {
state = SCE_L_CMDOPT;
} else if (latexLastWordIs(i, styler, "\\begin")) {
state = SCE_L_TAG;
} else if (latexLastWordIs(i, styler, "\\end")) {
state = SCE_L_TAG2;
} else if (latexLastWordIs(i, styler, "\\verb") && chNext != '*' && chNext != ' ') {
chVerbatimDelim = chNext;
state = SCE_L_VERBATIM;
} else {
latexStateReset(mode, state);
}
}
break;
case SCE_L_CMDOPT :
if (ch == ']') {
styler.ColourTo(i, state);
latexStateReset(mode, state);
}
break;
case SCE_L_TAG :
if (latexIsTagValid(i, lengthDoc, styler)) {
styler.ColourTo(i, state);
latexStateReset(mode, state);
if (latexLastWordIs(i, styler, "{verbatim}")) {
state = SCE_L_VERBATIM;
} else if (latexLastWordIs(i, styler, "{lstlisting}")) {
state = SCE_L_VERBATIM;
} else if (latexLastWordIs(i, styler, "{comment}")) {
state = SCE_L_COMMENT2;
} else if (latexLastWordIs(i, styler, "{math}") && mode == 0) {
mode = 1;
state = SCE_L_MATH;
} else if (latexLastWordIsMathEnv(i, styler) && mode == 0) {
mode = 2;
state = SCE_L_MATH2;
}
} else {
styler.ColourTo(i, SCE_L_ERROR);
latexStateReset(mode, state);
ch = styler.SafeGetCharAt(i);
if (ch == '\r' || ch == '\n') setMode(styler.GetLine(i), mode);
}
chNext = styler.SafeGetCharAt(i+1);
break;
case SCE_L_TAG2 :
if (latexIsTagValid(i, lengthDoc, styler)) {
styler.ColourTo(i, state);
latexStateReset(mode, state);
} else {
styler.ColourTo(i, SCE_L_ERROR);
latexStateReset(mode, state);
ch = styler.SafeGetCharAt(i);
if (ch == '\r' || ch == '\n') setMode(styler.GetLine(i), mode);
}
chNext = styler.SafeGetCharAt(i+1);
break;
case SCE_L_MATH :
switch (ch) {
case '\\' :
styler.ColourTo(i - 1, state);
if (latexIsLetter(chNext)) {
Sci_Position match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIs(match, styler, "{math}"))
mode = 0;
}
}
state = SCE_L_COMMAND;
} else if (latexIsSpecial(chNext)) {
styler.ColourTo(i + 1, SCE_L_SPECIAL);
i++;
chNext = styler.SafeGetCharAt(i + 1);
} else if (chNext == '\r' || chNext == '\n') {
styler.ColourTo(i, SCE_L_ERROR);
} else if (IsASCII(chNext)) {
if (chNext == ')') {
mode = 0;
state = SCE_L_DEFAULT;
}
styler.ColourTo(i + 1, SCE_L_SHORTCMD);
i++;
chNext = styler.SafeGetCharAt(i + 1);
}
break;
case '$' :
styler.ColourTo(i - 1, state);
styler.ColourTo(i, SCE_L_SHORTCMD);
mode = 0;
state = SCE_L_DEFAULT;
break;
case '%' :
styler.ColourTo(i - 1, state);
state = SCE_L_COMMENT;
break;
}
break;
case SCE_L_MATH2 :
switch (ch) {
case '\\' :
styler.ColourTo(i - 1, state);
if (latexIsLetter(chNext)) {
Sci_Position match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIsMathEnv(match, styler))
mode = 0;
}
}
state = SCE_L_COMMAND;
} else if (latexIsSpecial(chNext)) {
styler.ColourTo(i + 1, SCE_L_SPECIAL);
i++;
chNext = styler.SafeGetCharAt(i + 1);
} else if (chNext == '\r' || chNext == '\n') {
styler.ColourTo(i, SCE_L_ERROR);
} else if (IsASCII(chNext)) {
if (chNext == ']') {
mode = 0;
state = SCE_L_DEFAULT;
}
styler.ColourTo(i + 1, SCE_L_SHORTCMD);
i++;
chNext = styler.SafeGetCharAt(i + 1);
}
break;
case '$' :
styler.ColourTo(i - 1, state);
if (chNext == '$') {
styler.ColourTo(i + 1, SCE_L_SHORTCMD);
i++;
chNext = styler.SafeGetCharAt(i + 1);
mode = 0;
state = SCE_L_DEFAULT;
} else { // This may not be an error, e.g. \begin{equation}\text{$a$}\end{equation}
styler.ColourTo(i, SCE_L_SHORTCMD);
}
break;
case '%' :
styler.ColourTo(i - 1, state);
state = SCE_L_COMMENT;
break;
}
break;
case SCE_L_COMMENT :
if (ch == '\r' || ch == '\n') {
styler.ColourTo(i - 1, state);
latexStateReset(mode, state);
}
break;
case SCE_L_COMMENT2 :
if (ch == '\\') {
Sci_Position match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIs(match, styler, "{comment}")) {
styler.ColourTo(i - 1, state);
state = SCE_L_COMMAND;
}
}
}
}
break;
case SCE_L_VERBATIM :
if (ch == '\\') {
Sci_Position match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIs(match, styler, "{verbatim}")) {
styler.ColourTo(i - 1, state);
state = SCE_L_COMMAND;
} else if (latexLastWordIs(match, styler, "{lstlisting}")) {
styler.ColourTo(i - 1, state);
state = SCE_L_COMMAND;
}
}
}
} else if (chNext == chVerbatimDelim) {
styler.ColourTo(i + 1, state);
latexStateReset(mode, state);
chVerbatimDelim = '\0';
i++;
chNext = styler.SafeGetCharAt(i + 1);
} else if (chVerbatimDelim != '\0' && (ch == '\n' || ch == '\r')) {
styler.ColourTo(i, SCE_L_ERROR);
latexStateReset(mode, state);
chVerbatimDelim = '\0';
}
break;
}
}
if (lengthDoc == styler.Length()) truncModes(styler.GetLine(lengthDoc - 1));
styler.ColourTo(lengthDoc - 1, state);
styler.Flush();
}
static int latexFoldSaveToInt(const latexFoldSave &save) {
int sum = 0;
for (int i = 0; i <= save.structLev; ++i)
sum += save.openBegins[i];
return ((sum + save.structLev + SC_FOLDLEVELBASE) & SC_FOLDLEVELNUMBERMASK);
}
// Change folding state while processing a line
// Return the level before the first relevant command
void SCI_METHOD LexerLaTeX::Fold(Sci_PositionU startPos, Sci_Position length, int, IDocument *pAccess) {
const char *structWords[7] = {"part", "chapter", "section", "subsection",
"subsubsection", "paragraph", "subparagraph"};
Accessor styler(pAccess, &props);
Sci_PositionU endPos = startPos + length;
Sci_Position curLine = styler.GetLine(startPos);
latexFoldSave save;
getSave(curLine - 1, save);
do {
char ch, buf[16];
Sci_Position i, j;
int lev = -1;
bool needFold = false;
for (i = static_cast<Sci_Position>(startPos); i < static_cast<Sci_Position>(endPos); ++i) {
ch = styler.SafeGetCharAt(i);
if (ch == '\r' || ch == '\n') break;
if (ch != '\\' || styler.StyleAt(i) != SCE_L_COMMAND) continue;
for (j = 0; j < 15 && i + 1 < static_cast<Sci_Position>(endPos); ++j, ++i) {
buf[j] = styler.SafeGetCharAt(i + 1);
if (!latexIsLetter(buf[j])) break;
}
buf[j] = '\0';
if (strcmp(buf, "begin") == 0) {
if (lev < 0) lev = latexFoldSaveToInt(save);
++save.openBegins[save.structLev];
needFold = true;
}
else if (strcmp(buf, "end") == 0) {
while (save.structLev > 0 && save.openBegins[save.structLev] == 0)
--save.structLev;
if (lev < 0) lev = latexFoldSaveToInt(save);
if (save.openBegins[save.structLev] > 0) --save.openBegins[save.structLev];
}
else {
for (j = 0; j < 7; ++j)
if (strcmp(buf, structWords[j]) == 0) break;
if (j >= 7) continue;
save.structLev = j; // level before the command
for (j = save.structLev + 1; j < 8; ++j) {
save.openBegins[save.structLev] += save.openBegins[j];
save.openBegins[j] = 0;
}
if (lev < 0) lev = latexFoldSaveToInt(save);
++save.structLev; // level after the command
needFold = true;
}
}
if (lev < 0) lev = latexFoldSaveToInt(save);
if (needFold) lev |= SC_FOLDLEVELHEADERFLAG;
styler.SetLevel(curLine, lev);
setSave(curLine, save);
++curLine;
startPos = styler.LineStart(curLine);
if (static_cast<Sci_Position>(startPos) == styler.Length()) {
lev = latexFoldSaveToInt(save);
styler.SetLevel(curLine, lev);
setSave(curLine, save);
truncSaves(curLine);
}
} while (startPos < endPos);
styler.Flush();
}
static const char *const emptyWordListDesc[] = {
0
};
LexerModule lmLatex(SCLEX_LATEX, LexerLaTeX::LexerFactoryLaTeX, "latex", emptyWordListDesc);

View File

@ -0,0 +1,286 @@
// Scintilla source code edit control
/** @file LexLisp.cxx
** Lexer for Lisp.
** Written by Alexey Yutkin.
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// 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;
#define SCE_LISP_CHARACTER 29
#define SCE_LISP_MACRO 30
#define SCE_LISP_MACRO_DISPATCH 31
static inline bool isLispoperator(char ch) {
if (IsASCII(ch) && isalnum(ch))
return false;
if (ch == '\'' || ch == '`' || ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == '{' || ch == '}')
return true;
return false;
}
static inline bool isLispwordstart(char ch) {
return IsASCII(ch) && ch != ';' && !isspacechar(ch) && !isLispoperator(ch) &&
ch != '\n' && ch != '\r' && ch != '\"';
}
static void classifyWordLisp(Sci_PositionU start, Sci_PositionU end, WordList &keywords, WordList &keywords_kw, Accessor &styler) {
assert(end >= start);
char s[100];
Sci_PositionU i;
bool digit_flag = true;
for (i = 0; (i < end - start + 1) && (i < 99); i++) {
s[i] = styler[start + i];
s[i + 1] = '\0';
if (!isdigit(s[i]) && (s[i] != '.')) digit_flag = false;
}
char chAttr = SCE_LISP_IDENTIFIER;
if(digit_flag) chAttr = SCE_LISP_NUMBER;
else {
if (keywords.InList(s)) {
chAttr = SCE_LISP_KEYWORD;
} else if (keywords_kw.InList(s)) {
chAttr = SCE_LISP_KEYWORD_KW;
} else if ((s[0] == '*' && s[i-1] == '*') ||
(s[0] == '+' && s[i-1] == '+')) {
chAttr = SCE_LISP_SPECIAL;
}
}
styler.ColourTo(end, chAttr);
return;
}
static void ColouriseLispDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
WordList &keywords = *keywordlists[0];
WordList &keywords_kw = *keywordlists[1];
styler.StartAt(startPos);
int state = initStyle, radix = -1;
char chNext = styler[startPos];
Sci_PositionU lengthDoc = startPos + length;
styler.StartSegment(startPos);
for (Sci_PositionU i = startPos; i < lengthDoc; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
if (styler.IsLeadByte(ch)) {
chNext = styler.SafeGetCharAt(i + 2);
i += 1;
continue;
}
if (state == SCE_LISP_DEFAULT) {
if (ch == '#') {
styler.ColourTo(i - 1, state);
radix = -1;
state = SCE_LISP_MACRO_DISPATCH;
} else if (ch == ':' && isLispwordstart(chNext)) {
styler.ColourTo(i - 1, state);
state = SCE_LISP_SYMBOL;
} else if (isLispwordstart(ch)) {
styler.ColourTo(i - 1, state);
state = SCE_LISP_IDENTIFIER;
}
else if (ch == ';') {
styler.ColourTo(i - 1, state);
state = SCE_LISP_COMMENT;
}
else if (isLispoperator(ch) || ch=='\'') {
styler.ColourTo(i - 1, state);
styler.ColourTo(i, SCE_LISP_OPERATOR);
if (ch=='\'' && isLispwordstart(chNext)) {
state = SCE_LISP_SYMBOL;
}
}
else if (ch == '\"') {
styler.ColourTo(i - 1, state);
state = SCE_LISP_STRING;
}
} else if (state == SCE_LISP_IDENTIFIER || state == SCE_LISP_SYMBOL) {
if (!isLispwordstart(ch)) {
if (state == SCE_LISP_IDENTIFIER) {
classifyWordLisp(styler.GetStartSegment(), i - 1, keywords, keywords_kw, styler);
} else {
styler.ColourTo(i - 1, state);
}
state = SCE_LISP_DEFAULT;
} /*else*/
if (isLispoperator(ch) || ch=='\'') {
styler.ColourTo(i - 1, state);
styler.ColourTo(i, SCE_LISP_OPERATOR);
if (ch=='\'' && isLispwordstart(chNext)) {
state = SCE_LISP_SYMBOL;
}
}
} else if (state == SCE_LISP_MACRO_DISPATCH) {
if (!(IsASCII(ch) && isdigit(ch))) {
if (ch != 'r' && ch != 'R' && (i - styler.GetStartSegment()) > 1) {
state = SCE_LISP_DEFAULT;
} else {
switch (ch) {
case '|': state = SCE_LISP_MULTI_COMMENT; break;
case 'o':
case 'O': radix = 8; state = SCE_LISP_MACRO; break;
case 'x':
case 'X': radix = 16; state = SCE_LISP_MACRO; break;
case 'b':
case 'B': radix = 2; state = SCE_LISP_MACRO; break;
case '\\': state = SCE_LISP_CHARACTER; break;
case ':':
case '-':
case '+': state = SCE_LISP_MACRO; break;
case '\'': if (isLispwordstart(chNext)) {
state = SCE_LISP_SPECIAL;
} else {
styler.ColourTo(i - 1, SCE_LISP_DEFAULT);
styler.ColourTo(i, SCE_LISP_OPERATOR);
state = SCE_LISP_DEFAULT;
}
break;
default: if (isLispoperator(ch)) {
styler.ColourTo(i - 1, SCE_LISP_DEFAULT);
styler.ColourTo(i, SCE_LISP_OPERATOR);
}
state = SCE_LISP_DEFAULT;
break;
}
}
}
} else if (state == SCE_LISP_MACRO) {
if (isLispwordstart(ch) && (radix == -1 || IsADigit(ch, radix))) {
state = SCE_LISP_SPECIAL;
} else {
state = SCE_LISP_DEFAULT;
}
} else if (state == SCE_LISP_CHARACTER) {
if (isLispoperator(ch)) {
styler.ColourTo(i, SCE_LISP_SPECIAL);
state = SCE_LISP_DEFAULT;
} else if (isLispwordstart(ch)) {
styler.ColourTo(i, SCE_LISP_SPECIAL);
state = SCE_LISP_SPECIAL;
} else {
state = SCE_LISP_DEFAULT;
}
} else if (state == SCE_LISP_SPECIAL) {
if (!isLispwordstart(ch) || (radix != -1 && !IsADigit(ch, radix))) {
styler.ColourTo(i - 1, state);
state = SCE_LISP_DEFAULT;
}
if (isLispoperator(ch) || ch=='\'') {
styler.ColourTo(i - 1, state);
styler.ColourTo(i, SCE_LISP_OPERATOR);
if (ch=='\'' && isLispwordstart(chNext)) {
state = SCE_LISP_SYMBOL;
}
}
} else {
if (state == SCE_LISP_COMMENT) {
if (atEOL) {
styler.ColourTo(i - 1, state);
state = SCE_LISP_DEFAULT;
}
} else if (state == SCE_LISP_MULTI_COMMENT) {
if (ch == '|' && chNext == '#') {
i++;
chNext = styler.SafeGetCharAt(i + 1);
styler.ColourTo(i, state);
state = SCE_LISP_DEFAULT;
}
} else if (state == SCE_LISP_STRING) {
if (ch == '\\') {
if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
i++;
chNext = styler.SafeGetCharAt(i + 1);
}
} else if (ch == '\"') {
styler.ColourTo(i, state);
state = SCE_LISP_DEFAULT;
}
}
}
}
styler.ColourTo(lengthDoc - 1, state);
}
static void FoldLispDoc(Sci_PositionU startPos, Sci_Position length, int /* initStyle */, WordList *[],
Accessor &styler) {
Sci_PositionU lengthDoc = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
for (Sci_PositionU 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_LISP_OPERATOR) {
if (ch == '(' || ch == '[' || ch == '{') {
levelCurrent++;
} else if (ch == ')' || ch == ']' || ch == '}') {
levelCurrent--;
}
}
if (atEOL) {
int lev = levelPrev;
if (visibleChars == 0)
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 lispWordListDesc[] = {
"Functions and special operators",
"Keywords",
0
};
LexerModule lmLISP(SCLEX_LISP, ColouriseLispDoc, "lisp", FoldLispDoc, lispWordListDesc);

View File

@ -0,0 +1,216 @@
// Scintilla source code edit control
/** @file LexLout.cxx
** Lexer for the Basser Lout (>= version 3) typesetting language
**/
// Copyright 2003 by Kein-Hong Man <mkh@pl.jaring.my>
// 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;
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalpha(ch) || ch == '@' || ch == '_');
}
static inline bool IsAnOther(const int ch) {
return (ch < 0x80) && (ch == '{' || ch == '}' ||
ch == '!' || ch == '$' || ch == '%' || ch == '&' || ch == '\'' ||
ch == '(' || ch == ')' || ch == '*' || ch == '+' || ch == ',' ||
ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == ';' ||
ch == '<' || ch == '=' || ch == '>' || ch == '?' || ch == '[' ||
ch == ']' || ch == '^' || ch == '`' || ch == '|' || ch == '~');
}
static void ColouriseLoutDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler) {
WordList &keywords = *keywordlists[0];
WordList &keywords2 = *keywordlists[1];
WordList &keywords3 = *keywordlists[2];
int visibleChars = 0;
int firstWordInLine = 0;
int leadingAtSign = 0;
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
if (sc.atLineStart && (sc.state == SCE_LOUT_STRING)) {
// Prevent SCE_LOUT_STRINGEOL from leaking back to previous line
sc.SetState(SCE_LOUT_STRING);
}
// Determine if the current state should terminate.
if (sc.state == SCE_LOUT_COMMENT) {
if (sc.atLineEnd) {
sc.SetState(SCE_LOUT_DEFAULT);
visibleChars = 0;
}
} else if (sc.state == SCE_LOUT_NUMBER) {
if (!IsADigit(sc.ch) && sc.ch != '.') {
sc.SetState(SCE_LOUT_DEFAULT);
}
} else if (sc.state == SCE_LOUT_STRING) {
if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_LOUT_DEFAULT);
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_LOUT_STRINGEOL);
sc.ForwardSetState(SCE_LOUT_DEFAULT);
visibleChars = 0;
}
} else if (sc.state == SCE_LOUT_IDENTIFIER) {
if (!IsAWordChar(sc.ch)) {
char s[100];
sc.GetCurrent(s, sizeof(s));
if (leadingAtSign) {
if (keywords.InList(s)) {
sc.ChangeState(SCE_LOUT_WORD);
} else {
sc.ChangeState(SCE_LOUT_WORD4);
}
} else if (firstWordInLine && keywords3.InList(s)) {
sc.ChangeState(SCE_LOUT_WORD3);
}
sc.SetState(SCE_LOUT_DEFAULT);
}
} else if (sc.state == SCE_LOUT_OPERATOR) {
if (!IsAnOther(sc.ch)) {
char s[100];
sc.GetCurrent(s, sizeof(s));
if (keywords2.InList(s)) {
sc.ChangeState(SCE_LOUT_WORD2);
}
sc.SetState(SCE_LOUT_DEFAULT);
}
}
// Determine if a new state should be entered.
if (sc.state == SCE_LOUT_DEFAULT) {
if (sc.ch == '#') {
sc.SetState(SCE_LOUT_COMMENT);
} else if (sc.ch == '\"') {
sc.SetState(SCE_LOUT_STRING);
} else if (IsADigit(sc.ch) ||
(sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_LOUT_NUMBER);
} else if (IsAWordChar(sc.ch)) {
firstWordInLine = (visibleChars == 0);
leadingAtSign = (sc.ch == '@');
sc.SetState(SCE_LOUT_IDENTIFIER);
} else if (IsAnOther(sc.ch)) {
sc.SetState(SCE_LOUT_OPERATOR);
}
}
if (sc.atLineEnd) {
// Reset states to begining of colourise so no surprises
// if different sets of lines lexed.
visibleChars = 0;
}
if (!IsASpace(sc.ch)) {
visibleChars++;
}
}
sc.Complete();
}
static void FoldLoutDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[],
Accessor &styler) {
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position 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 (Sci_PositionU i = startPos; i < endPos; 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_LOUT_WORD) {
if (ch == '@') {
for (Sci_PositionU j = 0; j < 8; j++) {
if (!IsAWordChar(styler[i + j])) {
break;
}
s[j] = styler[i + j];
s[j + 1] = '\0';
}
if (strcmp(s, "@Begin") == 0) {
levelCurrent++;
} else if (strcmp(s, "@End") == 0) {
levelCurrent--;
}
}
} else if (style == SCE_LOUT_OPERATOR) {
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 loutWordLists[] = {
"Predefined identifiers",
"Predefined delimiters",
"Predefined keywords",
0,
};
LexerModule lmLout(SCLEX_LOUT, ColouriseLoutDoc, "lout", FoldLoutDoc, loutWordLists);

View File

@ -0,0 +1,635 @@
// 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 <cstdlib>
#include <cassert>
#include <cstring>
#include <string>
#include <string_view>
#include <vector>
#include <map>
#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"
#include "OptionSet.h"
#include "SubStyles.h"
#include "DefaultLexer.h"
using namespace Scintilla;
using namespace Lexilla;
namespace {
// Test for [=[ ... ]=] delimiters, returns 0 if it's only a [ or ],
// return 1 for [[ or ]], returns >=2 for [=[ or ]=] and so on.
// The maximum number of '=' characters allowed is 254.
int LongDelimCheck(StyleContext &sc) {
int sep = 1;
while (sc.GetRelative(sep) == '=' && sep < 0xFF)
sep++;
if (sc.GetRelative(sep) == sc.ch)
return sep;
return 0;
}
const char *const luaWordListDesc[] = {
"Keywords",
"Basic functions",
"String, (table) & math functions",
"(coroutines), I/O & system facilities",
"user1",
"user2",
"user3",
"user4",
nullptr
};
const char styleSubable[] = { SCE_LUA_IDENTIFIER, 0 };
const LexicalClass lexicalClasses[] = {
// Lexer Lua SCLEX_LUA SCE_LUA_:
0, "SCE_LUA_DEFAULT", "default", "White space: Visible only in View Whitespace mode (or if it has a back colour)",
1, "SCE_LUA_COMMENT", "comment", "Block comment (Lua 5.0)",
2, "SCE_LUA_COMMENTLINE", "comment line", "Line comment",
3, "SCE_LUA_COMMENTDOC", "comment documentation", "Doc comment",
4, "SCE_LUA_NUMBER", "literal numeric", "Number",
5, "SCE_LUA_WORD", "keyword", "Keyword",
6, "SCE_LUA_STRING", "literal string", "(Double quoted) String",
7, "SCE_LUA_CHARACTER", "literal string character", "Character (Single quoted string)",
8, "SCE_LUA_LITERALSTRING", "literal string", "Literal string",
9, "SCE_LUA_PREPROCESSOR", "preprocessor", "Preprocessor (obsolete in Lua 4.0 and up)",
10, "SCE_LUA_OPERATOR", "operator", "Operators",
11, "SCE_LUA_IDENTIFIER", "identifier", "Identifier (everything else...)",
12, "SCE_LUA_STRINGEOL", "error literal string", "End of line where string is not closed",
13, "SCE_LUA_WORD2", "identifier", "Other keywords",
14, "SCE_LUA_WORD3", "identifier", "Other keywords",
15, "SCE_LUA_WORD4", "identifier", "Other keywords",
16, "SCE_LUA_WORD5", "identifier", "Other keywords",
17, "SCE_LUA_WORD6", "identifier", "Other keywords",
18, "SCE_LUA_WORD7", "identifier", "Other keywords",
19, "SCE_LUA_WORD8", "identifier", "Other keywords",
20, "SCE_LUA_LABEL", "label", "Labels",
};
// Options used for LexerLua
struct OptionsLua {
bool foldCompact = true;
};
struct OptionSetLua : public OptionSet<OptionsLua> {
OptionSetLua() {
DefineProperty("fold.compact", &OptionsLua::foldCompact);
DefineWordListSets(luaWordListDesc);
}
};
class LexerLua : public DefaultLexer {
WordList keywords;
WordList keywords2;
WordList keywords3;
WordList keywords4;
WordList keywords5;
WordList keywords6;
WordList keywords7;
WordList keywords8;
OptionsLua options;
OptionSetLua osLua;
SubStyles subStyles{styleSubable};
public:
explicit LexerLua() :
DefaultLexer("lua", SCLEX_LUA, lexicalClasses, std::size(lexicalClasses)) {
}
~LexerLua() override = default;
void SCI_METHOD Release() noexcept override {
delete this;
}
int SCI_METHOD Version() const noexcept override {
return lvRelease5;
}
const char *SCI_METHOD PropertyNames() noexcept override {
return osLua.PropertyNames();
}
int SCI_METHOD PropertyType(const char *name) override {
return osLua.PropertyType(name);
}
const char *SCI_METHOD DescribeProperty(const char *name) override {
return osLua.DescribeProperty(name);
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
const char *SCI_METHOD PropertyGet(const char *key) override {
return osLua.PropertyGet(key);
}
const char *SCI_METHOD DescribeWordListSets() noexcept override {
return osLua.DescribeWordListSets();
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
int SCI_METHOD AllocateSubStyles(int styleBase, int numberStyles) override {
return subStyles.Allocate(styleBase, numberStyles);
}
int SCI_METHOD SubStylesStart(int styleBase) override {
return subStyles.Start(styleBase);
}
int SCI_METHOD SubStylesLength(int styleBase) override {
return subStyles.Length(styleBase);
}
int SCI_METHOD StyleFromSubStyle(int subStyle) override {
const int styleBase = subStyles.BaseStyle(subStyle);
return styleBase;
}
int SCI_METHOD PrimaryStyleFromStyle(int style) override {
return style;
}
void SCI_METHOD FreeSubStyles() override {
subStyles.Free();
}
void SCI_METHOD SetIdentifiers(int style, const char *identifiers) override {
subStyles.SetIdentifiers(style, identifiers);
}
int SCI_METHOD DistanceToSecondaryStyles() override {
return 0;
}
const char *SCI_METHOD GetSubStyleBases() override {
return styleSubable;
}
static ILexer5 *LexerFactoryLua() {
return new LexerLua();
}
};
Sci_Position SCI_METHOD LexerLua::PropertySet(const char *key, const char *val) {
if (osLua.PropertySet(&options, key, val)) {
return 0;
}
return -1;
}
Sci_Position SCI_METHOD LexerLua::WordListSet(int n, const char *wl) {
WordList *wordListN = nullptr;
switch (n) {
case 0:
wordListN = &keywords;
break;
case 1:
wordListN = &keywords2;
break;
case 2:
wordListN = &keywords3;
break;
case 3:
wordListN = &keywords4;
break;
case 4:
wordListN = &keywords5;
break;
case 5:
wordListN = &keywords6;
break;
case 6:
wordListN = &keywords7;
break;
case 7:
wordListN = &keywords8;
break;
default:
break;
}
Sci_Position firstModification = -1;
if (wordListN) {
if (wordListN->Set(wl)) {
firstModification = 0;
}
}
return firstModification;
}
constexpr int maskSeparator = 0xFF;
constexpr int maskStringWs = 0x100;
constexpr int maskDocComment = 0x200;
void LexerLua::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
LexAccessor styler(pAccess);
// Accepts accented characters
const CharacterSet setWordStart(CharacterSet::setAlpha, "_", true);
const CharacterSet setWord(CharacterSet::setAlphaNum, "_", true);
// Not exactly following number definition (several dots are seen as OK, etc.)
// but probably enough in most cases. [pP] is for hex floats.
const CharacterSet setNumber(CharacterSet::setDigits, ".-+abcdefpABCDEFP");
const CharacterSet setExponent("eEpP");
const CharacterSet setLuaOperator("*/-+()={}~[];<>,.^%:#&|");
const CharacterSet setEscapeSkip("\"'\\");
const WordClassifier &classifierIdentifiers = subStyles.Classifier(SCE_LUA_IDENTIFIER);
Sci_Position currentLine = styler.GetLine(startPos);
// Initialize long string [[ ... ]] or block comment --[[ ... ]],
// if we are inside such a string. Block comment was introduced in Lua 5.0,
// blocks with separators [=[ ... ]=] in Lua 5.1.
// Continuation of a string (\z whitespace escaping) is controlled by stringWs.
int sepCount = 0;
int stringWs = 0;
int lastLineDocComment = 0;
if ((currentLine > 0) &&
AnyOf(initStyle, SCE_LUA_DEFAULT, SCE_LUA_LITERALSTRING, SCE_LUA_COMMENT, SCE_LUA_COMMENTDOC, SCE_LUA_STRING, SCE_LUA_CHARACTER)) {
const int lineState = styler.GetLineState(currentLine - 1);
sepCount = lineState & maskSeparator;
stringWs = lineState & maskStringWs;
lastLineDocComment = lineState & maskDocComment;
}
// results of identifier/keyword matching
Sci_Position idenPos = 0;
Sci_Position idenWordPos = 0;
int idenStyle = SCE_LUA_IDENTIFIER;
bool foundGoto = false;
// Do not leak onto next line
if (AnyOf(initStyle, SCE_LUA_STRINGEOL, SCE_LUA_COMMENTLINE, SCE_LUA_COMMENTDOC, SCE_LUA_PREPROCESSOR)) {
initStyle = SCE_LUA_DEFAULT;
}
StyleContext sc(startPos, length, initStyle, styler);
if (startPos == 0 && sc.ch == '#' && sc.chNext == '!') {
// shbang line: "#!" is a comment only if located at the start 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_DEFAULT:
case SCE_LUA_LITERALSTRING:
case SCE_LUA_COMMENT:
case SCE_LUA_COMMENTDOC:
case SCE_LUA_STRING:
case SCE_LUA_CHARACTER:
// Inside a literal string, block comment or string, we set the line state
styler.SetLineState(currentLine, lastLineDocComment | stringWs | sepCount);
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) {
if (sc.ch == ':' && sc.chPrev == ':') { // :: <label> :: forward scan
sc.Forward();
Sci_Position ln = 0;
while (IsASpaceOrTab(sc.GetRelative(ln))) // skip over spaces/tabs
ln++;
const Sci_Position ws1 = ln;
if (setWordStart.Contains(sc.GetRelative(ln))) {
int c = 0;
std::string s;
while (setWord.Contains(c = sc.GetRelative(ln))) { // get potential label
s.push_back(static_cast<char>(c));
ln++;
}
const Sci_Position lbl = ln;
if (!keywords.InList(s)) {
while (IsASpaceOrTab(sc.GetRelative(ln))) // skip over spaces/tabs
ln++;
const Sci_Position ws2 = ln - lbl;
if (sc.GetRelative(ln) == ':' && sc.GetRelative(ln + 1) == ':') {
// final :: found, complete valid label construct
sc.ChangeState(SCE_LUA_LABEL);
if (ws1) {
sc.SetState(SCE_LUA_DEFAULT);
sc.ForwardBytes(ws1);
}
sc.SetState(SCE_LUA_LABEL);
sc.ForwardBytes(lbl - ws1);
if (ws2) {
sc.SetState(SCE_LUA_DEFAULT);
sc.ForwardBytes(ws2);
}
sc.SetState(SCE_LUA_LABEL);
sc.ForwardBytes(2);
}
}
}
}
sc.SetState(SCE_LUA_DEFAULT);
} else if (sc.state == SCE_LUA_NUMBER) {
// We stop the number definition on non-numerical non-dot non-eEpP non-sign non-hexdigit char
if (!setNumber.Contains(sc.ch)) {
sc.SetState(SCE_LUA_DEFAULT);
} else if (sc.ch == '-' || sc.ch == '+') {
if (!setExponent.Contains(sc.chPrev))
sc.SetState(SCE_LUA_DEFAULT);
}
} else if (sc.state == SCE_LUA_IDENTIFIER) {
idenPos--; // commit already-scanned identifier/word parts
if (idenWordPos > 0) {
idenWordPos--;
sc.ChangeState(idenStyle);
sc.ForwardBytes(idenWordPos);
idenPos -= idenWordPos;
if (idenPos > 0) {
sc.SetState(SCE_LUA_IDENTIFIER);
sc.ForwardBytes(idenPos);
}
} else {
sc.ForwardBytes(idenPos);
}
sc.SetState(SCE_LUA_DEFAULT);
if (foundGoto) { // goto <label> forward scan
while (IsASpaceOrTab(sc.ch) && !sc.atLineEnd)
sc.Forward();
if (setWordStart.Contains(sc.ch)) {
sc.SetState(SCE_LUA_LABEL);
sc.Forward();
while (setWord.Contains(sc.ch))
sc.Forward();
std::string s;
sc.GetCurrentString(s, StyleContext::Transform::none);
if (keywords.InList(s)) // labels cannot be keywords
sc.ChangeState(SCE_LUA_WORD);
}
sc.SetState(SCE_LUA_DEFAULT);
}
} else if (AnyOf(sc.state, SCE_LUA_COMMENTLINE, SCE_LUA_COMMENTDOC, SCE_LUA_PREPROCESSOR)) {
if (sc.atLineEnd) {
sc.ForwardSetState(SCE_LUA_DEFAULT);
}
} else if (sc.state == SCE_LUA_STRING) {
if (stringWs) {
if (!IsASpace(sc.ch))
stringWs = 0;
}
if (sc.ch == '\\') {
if (setEscapeSkip.Contains(sc.chNext)) {
sc.Forward();
} else if (sc.chNext == 'z') {
sc.Forward();
stringWs = maskStringWs;
}
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_LUA_DEFAULT);
} else if (stringWs == 0 && sc.atLineEnd) {
sc.ChangeState(SCE_LUA_STRINGEOL);
sc.ForwardSetState(SCE_LUA_DEFAULT);
}
} else if (sc.state == SCE_LUA_CHARACTER) {
if (stringWs) {
if (!IsASpace(sc.ch))
stringWs = 0;
}
if (sc.ch == '\\') {
if (setEscapeSkip.Contains(sc.chNext)) {
sc.Forward();
} else if (sc.chNext == 'z') {
sc.Forward();
stringWs = maskStringWs;
}
} else if (sc.ch == '\'') {
sc.ForwardSetState(SCE_LUA_DEFAULT);
} else if (stringWs == 0 && sc.atLineEnd) {
sc.ChangeState(SCE_LUA_STRINGEOL);
sc.ForwardSetState(SCE_LUA_DEFAULT);
}
} else if (sc.ch == ']' && (sc.state == SCE_LUA_LITERALSTRING || sc.state == SCE_LUA_COMMENT)) {
const int sep = LongDelimCheck(sc);
if (sep == sepCount) { // ]=]-style delim
sc.Forward(sep);
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);
if (sc.ch == '0' && AnyOf(sc.chNext, 'x', 'X')) {
sc.Forward();
}
} else if (setWordStart.Contains(sc.ch)) {
// For matching various identifiers with dots and colons, multiple
// matches are done as identifier segments are added. Longest match is
// set to a word style. The non-matched part is in identifier style.
std::string ident;
idenPos = 0;
idenWordPos = 0;
idenStyle = SCE_LUA_IDENTIFIER;
foundGoto = false;
int cNext = 0;
do {
int c = 0;
const Sci_Position idenPosOld = idenPos;
std::string identSeg;
identSeg += static_cast<char>(sc.GetRelative(idenPos++));
while (setWord.Contains(c = sc.GetRelative(idenPos))) {
identSeg += static_cast<char>(c);
idenPos++;
}
if (keywords.InList(identSeg) && (idenPosOld > 0)) {
idenPos = idenPosOld - 1; // keywords cannot mix
ident.pop_back();
break;
}
ident += identSeg;
int newStyle = SCE_LUA_IDENTIFIER;
if (keywords.InList(ident)) {
newStyle = SCE_LUA_WORD;
} else if (keywords2.InList(ident)) {
newStyle = SCE_LUA_WORD2;
} else if (keywords3.InList(ident)) {
newStyle = SCE_LUA_WORD3;
} else if (keywords4.InList(ident)) {
newStyle = SCE_LUA_WORD4;
} else if (keywords5.InList(ident)) {
newStyle = SCE_LUA_WORD5;
} else if (keywords6.InList(ident)) {
newStyle = SCE_LUA_WORD6;
} else if (keywords7.InList(ident)) {
newStyle = SCE_LUA_WORD7;
} else if (keywords8.InList(ident)) {
newStyle = SCE_LUA_WORD8;
} else {
const int subStyle = classifierIdentifiers.ValueFor(ident);
if (subStyle >= 0) {
newStyle = subStyle;
}
}
if (newStyle != SCE_LUA_IDENTIFIER) {
idenStyle = newStyle;
idenWordPos = idenPos;
}
if (idenStyle == SCE_LUA_WORD) // keywords cannot mix
break;
cNext = sc.GetRelative(idenPos + 1);
if ((c == '.' || c == ':') && setWordStart.Contains(cNext)) {
ident += static_cast<char>(c);
idenPos++;
} else {
cNext = 0;
}
} while (cNext);
if ((idenStyle == SCE_LUA_WORD) && (ident == "goto")) {
foundGoto = true;
}
sc.SetState(SCE_LUA_IDENTIFIER);
} else if (sc.ch == '\"') {
sc.SetState(SCE_LUA_STRING);
stringWs = 0;
} else if (sc.ch == '\'') {
sc.SetState(SCE_LUA_CHARACTER);
stringWs = 0;
} else if (sc.ch == '[') {
sepCount = LongDelimCheck(sc);
if (sepCount == 0) {
sc.SetState(SCE_LUA_OPERATOR);
} else {
sc.SetState(SCE_LUA_LITERALSTRING);
sc.Forward(sepCount);
}
} else if (sc.Match('-', '-')) {
sc.SetState(lastLineDocComment ? SCE_LUA_COMMENTDOC : SCE_LUA_COMMENTLINE);
if (sc.Match("--[")) {
sc.Forward(2);
sepCount = LongDelimCheck(sc);
if (sepCount > 0) {
sc.ChangeState(SCE_LUA_COMMENT);
sc.Forward(sepCount);
}
} else if (sc.Match("---")) {
sc.SetState(SCE_LUA_COMMENTDOC);
lastLineDocComment = maskDocComment;
} else {
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 (setLuaOperator.Contains(sc.ch)) {
sc.SetState(SCE_LUA_OPERATOR);
}
if (!AnyOf(sc.state, SCE_LUA_DEFAULT, SCE_LUA_COMMENTDOC)) {
lastLineDocComment = 0;
}
}
}
sc.Complete();
}
void LexerLua::Fold(Sci_PositionU startPos_, Sci_Position length, int initStyle, IDocument *pAccess) {
LexAccessor styler(pAccess);
const Sci_Position startPos = startPos_;
const Sci_Position lengthDoc = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
const bool foldCompact = options.foldCompact;
int style = initStyle;
int styleNext = styler.StyleIndexAt(startPos);
for (Sci_Position i = startPos; i < lengthDoc; i++) {
const char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
const int stylePrev = style;
style = styleNext;
styleNext = styler.StyleIndexAt(i + 1);
const bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
if (style == SCE_LUA_WORD) {
// Fixed list of folding words: if, do, function, repeat, end, until
// Must fix up next line with initial characters if any new words added.
if ((style != stylePrev) && AnyOf(ch, 'i', 'd', 'f', 'e', 'r', 'u')) {
std::string s;
for (Sci_Position j = 0; j < 8; j++) { // 8 is length of longest: function
if (!iswordchar(styler[i + j])) {
break;
}
s.push_back(styler[i + j]);
}
if (s == "if" || s == "do" || s == "function" || s == "repeat") {
levelCurrent++;
}
if (s == "end" || s == "until") {
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 (stylePrev != style) {
levelCurrent++;
} else if (styleNext != style) {
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
const int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}
}
LexerModule lmLua(SCLEX_LUA, LexerLua::LexerFactoryLua, "lua", luaWordListDesc);

View File

@ -0,0 +1,186 @@
// Scintilla source code edit control
// Encoding: UTF-8
/** @file LexMMIXAL.cxx
** Lexer for MMIX Assembler Language.
** Written by Christoph Hösler <christoph.hoesler@student.uni-tuebingen.de>
** For information about MMIX visit http://www-cs-faculty.stanford.edu/~knuth/mmix.html
**/
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// 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;
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == ':' || ch == '_');
}
static inline bool isMMIXALOperator(char ch) {
if (IsASCII(ch) && isalnum(ch))
return false;
if (ch == '+' || ch == '-' || ch == '|' || ch == '^' ||
ch == '*' || ch == '/' ||
ch == '%' || ch == '<' || ch == '>' || ch == '&' ||
ch == '~' || ch == '$' ||
ch == ',' || ch == '(' || ch == ')' ||
ch == '[' || ch == ']')
return true;
return false;
}
static void ColouriseMMIXALDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
WordList &opcodes = *keywordlists[0];
WordList &special_register = *keywordlists[1];
WordList &predef_symbols = *keywordlists[2];
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward())
{
// No EOL continuation
if (sc.atLineStart) {
if (sc.ch == '@' && sc.chNext == 'i') {
sc.SetState(SCE_MMIXAL_INCLUDE);
} else {
sc.SetState(SCE_MMIXAL_LEADWS);
}
}
// Check if first non whitespace character in line is alphanumeric
if (sc.state == SCE_MMIXAL_LEADWS && !isspace(sc.ch)) { // LEADWS
if(!IsAWordChar(sc.ch)) {
sc.SetState(SCE_MMIXAL_COMMENT);
} else {
if(sc.atLineStart) {
sc.SetState(SCE_MMIXAL_LABEL);
} else {
sc.SetState(SCE_MMIXAL_OPCODE_PRE);
}
}
}
// Determine if the current state should terminate.
if (sc.state == SCE_MMIXAL_OPERATOR) { // OPERATOR
sc.SetState(SCE_MMIXAL_OPERANDS);
} else if (sc.state == SCE_MMIXAL_NUMBER) { // NUMBER
if (!isdigit(sc.ch)) {
if (IsAWordChar(sc.ch)) {
sc.ChangeState(SCE_MMIXAL_REF);
sc.SetState(SCE_MMIXAL_REF);
} else {
sc.SetState(SCE_MMIXAL_OPERANDS);
}
}
} else if (sc.state == SCE_MMIXAL_LABEL) { // LABEL
if (!IsAWordChar(sc.ch) ) {
sc.SetState(SCE_MMIXAL_OPCODE_PRE);
}
} else if (sc.state == SCE_MMIXAL_REF) { // REF
if (!IsAWordChar(sc.ch) ) {
char s0[100];
sc.GetCurrent(s0, sizeof(s0));
const char *s = s0;
if (*s == ':') { // ignore base prefix for match
++s;
}
if (special_register.InList(s)) {
sc.ChangeState(SCE_MMIXAL_REGISTER);
} else if (predef_symbols.InList(s)) {
sc.ChangeState(SCE_MMIXAL_SYMBOL);
}
sc.SetState(SCE_MMIXAL_OPERANDS);
}
} else if (sc.state == SCE_MMIXAL_OPCODE_PRE) { // OPCODE_PRE
if (!isspace(sc.ch)) {
sc.SetState(SCE_MMIXAL_OPCODE);
}
} else if (sc.state == SCE_MMIXAL_OPCODE) { // OPCODE
if (!IsAWordChar(sc.ch) ) {
char s[100];
sc.GetCurrent(s, sizeof(s));
if (opcodes.InList(s)) {
sc.ChangeState(SCE_MMIXAL_OPCODE_VALID);
} else {
sc.ChangeState(SCE_MMIXAL_OPCODE_UNKNOWN);
}
sc.SetState(SCE_MMIXAL_OPCODE_POST);
}
} else if (sc.state == SCE_MMIXAL_STRING) { // STRING
if (sc.ch == '\"') {
sc.ForwardSetState(SCE_MMIXAL_OPERANDS);
} else if (sc.atLineEnd) {
sc.ForwardSetState(SCE_MMIXAL_OPERANDS);
}
} else if (sc.state == SCE_MMIXAL_CHAR) { // CHAR
if (sc.ch == '\'') {
sc.ForwardSetState(SCE_MMIXAL_OPERANDS);
} else if (sc.atLineEnd) {
sc.ForwardSetState(SCE_MMIXAL_OPERANDS);
}
} else if (sc.state == SCE_MMIXAL_REGISTER) { // REGISTER
if (!isdigit(sc.ch)) {
sc.SetState(SCE_MMIXAL_OPERANDS);
}
} else if (sc.state == SCE_MMIXAL_HEX) { // HEX
if (!isxdigit(sc.ch)) {
sc.SetState(SCE_MMIXAL_OPERANDS);
}
}
// Determine if a new state should be entered.
if (sc.state == SCE_MMIXAL_OPCODE_POST || // OPCODE_POST
sc.state == SCE_MMIXAL_OPERANDS) { // OPERANDS
if (sc.state == SCE_MMIXAL_OPERANDS && isspace(sc.ch)) {
sc.SetState(SCE_MMIXAL_COMMENT);
} else if (isdigit(sc.ch)) {
sc.SetState(SCE_MMIXAL_NUMBER);
} else if (IsAWordChar(sc.ch) || sc.Match('@')) {
sc.SetState(SCE_MMIXAL_REF);
} else if (sc.Match('\"')) {
sc.SetState(SCE_MMIXAL_STRING);
} else if (sc.Match('\'')) {
sc.SetState(SCE_MMIXAL_CHAR);
} else if (sc.Match('$')) {
sc.SetState(SCE_MMIXAL_REGISTER);
} else if (sc.Match('#')) {
sc.SetState(SCE_MMIXAL_HEX);
} else if (isMMIXALOperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_MMIXAL_OPERATOR);
}
}
}
sc.Complete();
}
static const char * const MMIXALWordListDesc[] = {
"Operation Codes",
"Special Register",
"Predefined Symbols",
0
};
LexerModule lmMMIXAL(SCLEX_MMIXAL, ColouriseMMIXALDoc, "mmixal", 0, MMIXALWordListDesc);

View File

@ -0,0 +1,192 @@
// Scintilla source code edit control
/** @file LexMPT.cxx
** Lexer for MPT specific files. Based on LexOthers.cxx
** LOT = the text log file created by the MPT application while running a test program
** Other MPT specific files to be added later.
**/
// Copyright 2003 by Marius Gheorghe <mgheorghe@cabletest.com>
// 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;
static int GetLotLineState(std::string &line) {
if (line.length()) {
// Most of the time the first non-blank character in line determines that line's type
// Now finds the first non-blank character
unsigned i; // Declares counter here to make it persistent after the for loop
for (i = 0; i < line.length(); ++i) {
if (!(IsASCII(line[i]) && isspace(line[i])))
break;
}
// Checks if it was a blank line
if (i == line.length())
return SCE_LOT_DEFAULT;
switch (line[i]) {
case '*': // Fail measurement
return SCE_LOT_FAIL;
case '+': // Header
case '|': // Header
return SCE_LOT_HEADER;
case ':': // Set test limits
return SCE_LOT_SET;
case '-': // Section break
return SCE_LOT_BREAK;
default: // Any other line
// Checks for message at the end of lot file
if (line.find("PASSED") != std::string::npos) {
return SCE_LOT_PASS;
}
else if (line.find("FAILED") != std::string::npos) {
return SCE_LOT_FAIL;
}
else if (line.find("ABORTED") != std::string::npos) {
return SCE_LOT_ABORT;
}
else {
return i ? SCE_LOT_PASS : SCE_LOT_DEFAULT;
}
}
}
else {
return SCE_LOT_DEFAULT;
}
}
static void ColourizeLotDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
styler.StartAt(startPos);
styler.StartSegment(startPos);
bool atLineStart = true;// Arms the 'at line start' flag
char chNext = styler.SafeGetCharAt(startPos);
std::string line("");
line.reserve(256); // Lot lines are less than 256 chars long most of the time. This should avoid reallocations
// Styles LOT document
Sci_PositionU i; // Declared here because it's used after the for loop
for (i = startPos; i < startPos + length; ++i) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
line += ch;
atLineStart = false;
// LOT files are only used on the Win32 platform, thus EOL == CR+LF
// Searches for the end of line
if (ch == '\r' && chNext == '\n') {
line += chNext; // Gets the '\n'
++i; // Advances past the '\n'
chNext = styler.SafeGetCharAt(i + 1); // Gets character of next line
styler.ColourTo(i, GetLotLineState(line));
line = "";
atLineStart = true; // Arms flag for next line
}
}
// Last line may not have a line ending
if (!atLineStart) {
styler.ColourTo(i - 1, GetLotLineState(line));
}
}
// Folds an MPT LOT file: the blocks that can be folded are:
// sections (headed by a set line)
// passes (contiguous pass results within a section)
// fails (contiguous fail results within a section)
static void FoldLotDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
bool foldCompact = styler.GetPropertyInt("fold.compact", 0) != 0;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
char chNext = styler.SafeGetCharAt(startPos);
int style = SCE_LOT_DEFAULT;
int styleNext = styler.StyleAt(startPos);
int lev = SC_FOLDLEVELBASE;
// Gets style of previous line if not at the beginning of the document
if (startPos > 1)
style = styler.StyleAt(startPos - 2);
for (Sci_PositionU i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if (ch == '\r' && chNext == '\n') {
// TO DO:
// Should really get the state of the previous line from the styler
int stylePrev = style;
style = styleNext;
styleNext = styler.StyleAt(i + 2);
switch (style) {
/*
case SCE_LOT_SET:
lev = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
break;
*/
case SCE_LOT_FAIL:
/*
if (stylePrev != SCE_LOT_FAIL)
lev = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
else
lev = SC_FOLDLEVELBASE + 1;
*/
lev = SC_FOLDLEVELBASE;
break;
default:
if (lineCurrent == 0 || stylePrev == SCE_LOT_FAIL)
lev = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
else
lev = SC_FOLDLEVELBASE + 1;
if (visibleChars == 0 && foldCompact)
lev |= SC_FOLDLEVELWHITEFLAG;
break;
}
if (lev != styler.LevelAt(lineCurrent))
styler.SetLevel(lineCurrent, lev);
lineCurrent++;
visibleChars = 0;
}
if (!isspacechar(ch))
visibleChars++;
}
int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
styler.SetLevel(lineCurrent, lev | flagsNext);
}
static const char * const emptyWordListDesc[] = {
0
};
LexerModule lmLot(SCLEX_LOT, ColourizeLotDoc, "lot", FoldLotDoc, emptyWordListDesc);

View File

@ -0,0 +1,370 @@
// Scintilla source code edit control
/** @file LexMSSQL.cxx
** Lexer for MSSQL.
**/
// By Filip Yaghob <fyaghob@gmail.com>
// 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;
#define KW_MSSQL_STATEMENTS 0
#define KW_MSSQL_DATA_TYPES 1
#define KW_MSSQL_SYSTEM_TABLES 2
#define KW_MSSQL_GLOBAL_VARIABLES 3
#define KW_MSSQL_FUNCTIONS 4
#define KW_MSSQL_STORED_PROCEDURES 5
#define KW_MSSQL_OPERATORS 6
static char classifyWordSQL(Sci_PositionU start,
Sci_PositionU end,
WordList *keywordlists[],
Accessor &styler,
unsigned int actualState,
unsigned int prevState) {
char s[256];
bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
WordList &kwStatements = *keywordlists[KW_MSSQL_STATEMENTS];
WordList &kwDataTypes = *keywordlists[KW_MSSQL_DATA_TYPES];
WordList &kwSystemTables = *keywordlists[KW_MSSQL_SYSTEM_TABLES];
WordList &kwGlobalVariables = *keywordlists[KW_MSSQL_GLOBAL_VARIABLES];
WordList &kwFunctions = *keywordlists[KW_MSSQL_FUNCTIONS];
WordList &kwStoredProcedures = *keywordlists[KW_MSSQL_STORED_PROCEDURES];
WordList &kwOperators = *keywordlists[KW_MSSQL_OPERATORS];
for (Sci_PositionU i = 0; i < end - start + 1 && i < 128; i++) {
s[i] = static_cast<char>(tolower(styler[start + i]));
s[i + 1] = '\0';
}
char chAttr = SCE_MSSQL_IDENTIFIER;
if (actualState == SCE_MSSQL_GLOBAL_VARIABLE) {
if (kwGlobalVariables.InList(&s[2]))
chAttr = SCE_MSSQL_GLOBAL_VARIABLE;
} else if (wordIsNumber) {
chAttr = SCE_MSSQL_NUMBER;
} else if (prevState == SCE_MSSQL_DEFAULT_PREF_DATATYPE) {
// Look first in datatypes
if (kwDataTypes.InList(s))
chAttr = SCE_MSSQL_DATATYPE;
else if (kwOperators.InList(s))
chAttr = SCE_MSSQL_OPERATOR;
else if (kwStatements.InList(s))
chAttr = SCE_MSSQL_STATEMENT;
else if (kwSystemTables.InList(s))
chAttr = SCE_MSSQL_SYSTABLE;
else if (kwFunctions.InList(s))
chAttr = SCE_MSSQL_FUNCTION;
else if (kwStoredProcedures.InList(s))
chAttr = SCE_MSSQL_STORED_PROCEDURE;
} else {
if (kwOperators.InList(s))
chAttr = SCE_MSSQL_OPERATOR;
else if (kwStatements.InList(s))
chAttr = SCE_MSSQL_STATEMENT;
else if (kwSystemTables.InList(s))
chAttr = SCE_MSSQL_SYSTABLE;
else if (kwFunctions.InList(s))
chAttr = SCE_MSSQL_FUNCTION;
else if (kwStoredProcedures.InList(s))
chAttr = SCE_MSSQL_STORED_PROCEDURE;
else if (kwDataTypes.InList(s))
chAttr = SCE_MSSQL_DATATYPE;
}
styler.ColourTo(end, chAttr);
return chAttr;
}
static void ColouriseMSSQLDoc(Sci_PositionU startPos, Sci_Position length,
int initStyle, WordList *keywordlists[], Accessor &styler) {
styler.StartAt(startPos);
bool fold = styler.GetPropertyInt("fold") != 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int spaceFlags = 0;
int state = initStyle;
int prevState = initStyle;
char chPrev = ' ';
char chNext = styler[startPos];
int nesting = 0;
if (lineCurrent >= 1) {
nesting = styler.GetLineState(lineCurrent - 1);
}
styler.StartSegment(startPos);
Sci_PositionU lengthDoc = startPos + length;
for (Sci_PositionU i = startPos; i < lengthDoc; i++) {
const Sci_Position lineStartNext = styler.LineStart(lineCurrent + 1);
const bool atEOL = (static_cast<Sci_Position>(i) == (lineStartNext - 1));
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags);
int lev = indentCurrent;
if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
// Only non whitespace lines can be headers
int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags);
if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) {
lev |= SC_FOLDLEVELHEADERFLAG;
}
}
if (fold) {
styler.SetLevel(lineCurrent, lev);
}
}
if (styler.IsLeadByte(ch)) {
chNext = styler.SafeGetCharAt(i + 2);
chPrev = ' ';
i += 1;
continue;
}
// When the last char isn't part of the state (have to deal with it too)...
if ( (state == SCE_MSSQL_IDENTIFIER) ||
(state == SCE_MSSQL_STORED_PROCEDURE) ||
(state == SCE_MSSQL_DATATYPE) ||
//~ (state == SCE_MSSQL_COLUMN_NAME) ||
(state == SCE_MSSQL_FUNCTION) ||
//~ (state == SCE_MSSQL_GLOBAL_VARIABLE) ||
(state == SCE_MSSQL_VARIABLE)) {
if (!iswordchar(ch)) {
int stateTmp;
if ((state == SCE_MSSQL_VARIABLE) || (state == SCE_MSSQL_COLUMN_NAME)) {
styler.ColourTo(i - 1, state);
stateTmp = state;
} else
stateTmp = classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState);
prevState = state;
if (stateTmp == SCE_MSSQL_IDENTIFIER || stateTmp == SCE_MSSQL_VARIABLE)
state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
else
state = SCE_MSSQL_DEFAULT;
}
} else if (state == SCE_MSSQL_LINE_COMMENT) {
if (ch == '\r' || ch == '\n') {
styler.ColourTo(i - 1, state);
prevState = state;
state = SCE_MSSQL_DEFAULT;
}
} else if (state == SCE_MSSQL_GLOBAL_VARIABLE) {
if ((ch != '@') && !iswordchar(ch)) {
classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState);
prevState = state;
state = SCE_MSSQL_DEFAULT;
}
}
// If is the default or one of the above succeeded
if (state == SCE_MSSQL_DEFAULT || state == SCE_MSSQL_DEFAULT_PREF_DATATYPE) {
if (iswordstart(ch)) {
styler.ColourTo(i - 1, state);
prevState = state;
state = SCE_MSSQL_IDENTIFIER;
} else if (ch == '/' && chNext == '*') {
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
prevState = state;
state = SCE_MSSQL_COMMENT;
} else if (ch == '-' && chNext == '-') {
styler.ColourTo(i - 1, state);
prevState = state;
state = SCE_MSSQL_LINE_COMMENT;
} else if (ch == '\'') {
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
prevState = state;
state = SCE_MSSQL_STRING;
} else if (ch == '"') {
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
prevState = state;
state = SCE_MSSQL_COLUMN_NAME;
} else if (ch == '[') {
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
prevState = state;
state = SCE_MSSQL_COLUMN_NAME_2;
} else if (isoperator(ch)) {
styler.ColourTo(i - 1, state);
styler.ColourTo(i, SCE_MSSQL_OPERATOR);
//~ style = SCE_MSSQL_DEFAULT;
prevState = state;
state = SCE_MSSQL_DEFAULT;
} else if (ch == '@') {
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
prevState = state;
if (chNext == '@') {
state = SCE_MSSQL_GLOBAL_VARIABLE;
// i += 2;
} else
state = SCE_MSSQL_VARIABLE;
}
// When the last char is part of the state...
} else if (state == SCE_MSSQL_COMMENT) {
if (ch == '/' && chNext == '*')
nesting++;
else if (ch == '/' && chPrev == '*') {
if (nesting > 0)
nesting--;
else if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_MSSQL_COMMENT) &&
(styler.GetStartSegment() == startPos)))) {
styler.ColourTo(i, state);
//~ state = SCE_MSSQL_COMMENT;
prevState = state;
state = SCE_MSSQL_DEFAULT;
}
}
} else if (state == SCE_MSSQL_STRING) {
if (ch == '\'') {
if ( chNext == '\'' ) {
i++;
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
} else {
styler.ColourTo(i, state);
prevState = state;
state = SCE_MSSQL_DEFAULT;
//i++;
}
//ch = chNext;
//chNext = styler.SafeGetCharAt(i + 1);
}
} else if (state == SCE_MSSQL_COLUMN_NAME) {
if (ch == '"') {
if (chNext == '"') {
i++;
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
} else {
styler.ColourTo(i, state);
prevState = state;
state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
//i++;
}
}
} else if (state == SCE_MSSQL_COLUMN_NAME_2) {
if (ch == ']') {
styler.ColourTo(i, state);
prevState = state;
state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
//i++;
}
}
if (atEOL)
styler.SetLineState(lineCurrent++, (state == SCE_MSSQL_COMMENT) ? nesting : 0);
chPrev = ch;
}
styler.ColourTo(lengthDoc - 1, state);
}
static void FoldMSSQLDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
bool inComment = (styler.StyleAt(startPos-1) == SCE_MSSQL_COMMENT);
char s[10] = "";
for (Sci_PositionU i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
int style = styler.StyleAt(i);
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
// Comment folding
if (foldComment) {
if (!inComment && (style == SCE_MSSQL_COMMENT))
levelCurrent++;
else if (inComment && (style != SCE_MSSQL_COMMENT))
levelCurrent--;
inComment = (style == SCE_MSSQL_COMMENT);
}
if (style == SCE_MSSQL_STATEMENT) {
// Folding between begin or case and end
if (ch == 'b' || ch == 'B' || ch == 'c' || ch == 'C' || ch == 'e' || ch == 'E') {
for (Sci_PositionU j = 0; j < 5; j++) {
if (!iswordchar(styler[i + j])) {
break;
}
s[j] = static_cast<char>(tolower(styler[i + j]));
s[j + 1] = '\0';
}
if ((strcmp(s, "begin") == 0) || (strcmp(s, "case") == 0)) {
levelCurrent++;
}
if (strcmp(s, "end") == 0) {
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 sqlWordListDesc[] = {
"Statements",
"Data Types",
"System tables",
"Global variables",
"Functions",
"System Stored Procedures",
"Operators",
0,
};
LexerModule lmMSSQL(SCLEX_MSSQL, ColouriseMSSQLDoc, "mssql", FoldMSSQLDoc, sqlWordListDesc);

View File

@ -0,0 +1,449 @@
// Scintilla source code edit control
/**
* @file LexMagik.cxx
* Lexer for GE(r) Smallworld(tm) MagikSF
*/
// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
// 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;
/**
* Is it a core character (C isalpha(), exclamation and question mark)
*
* \param ch The character
* \return True if ch is a character, False otherwise
*/
static inline bool IsAlphaCore(int ch) {
return (isalpha(ch) || ch == '!' || ch == '?');
}
/**
* Is it a character (IsAlphaCore() and underscore)
*
* \param ch The character
* \return True if ch is a character, False otherwise
*/
static inline bool IsAlpha(int ch) {
return (IsAlphaCore(ch) || ch == '_');
}
/**
* Is it a symbolic character (IsAlpha() and colon)
*
* \param ch The character
* \return True if ch is a character, False otherwise
*/
static inline bool IsAlphaSym(int ch) {
return (IsAlpha(ch) || ch == ':');
}
/**
* Is it a numerical character (IsAlpha() and 0 - 9)
*
* \param ch The character
* \return True if ch is a character, False otherwise
*/
static inline bool IsAlNum(int ch) {
return ((ch >= '0' && ch <= '9') || IsAlpha(ch));
}
/**
* Is it a symbolic numerical character (IsAlNum() and colon)
*
* \param ch The character
* \return True if ch is a character, False otherwise
*/
static inline bool IsAlNumSym(int ch) {
return (IsAlNum(ch) || ch == ':');
}
/**
* The lexer function
*
* \param startPos Where to start scanning
* \param length Where to scan to
* \param initStyle The style at the initial point, not used in this folder
* \param keywordlists The keywordslists, currently, number 5 is used
* \param styler The styler
*/
static void ColouriseMagikDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler) {
styler.StartAt(startPos);
WordList &keywords = *keywordlists[0];
WordList &pragmatics = *keywordlists[1];
WordList &containers = *keywordlists[2];
WordList &flow = *keywordlists[3];
WordList &characters = *keywordlists[4];
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
repeat:
if(sc.ch == '#') {
if (sc.chNext == '#') sc.SetState(SCE_MAGIK_HYPER_COMMENT);
else sc.SetState(SCE_MAGIK_COMMENT);
for(; sc.More() && !(sc.atLineEnd); sc.Forward());
sc.SetState(SCE_MAGIK_DEFAULT);
goto repeat;
}
if(sc.ch == '"') {
sc.SetState(SCE_MAGIK_STRING);
if(sc.More())
{
sc.Forward();
for(; sc.More() && sc.ch != '"'; sc.Forward());
}
sc.ForwardSetState(SCE_MAGIK_DEFAULT);
goto repeat;
}
// The default state
if(sc.state == SCE_MAGIK_DEFAULT) {
// A certain keyword has been detected
if (sc.ch == '_' && (
sc.currentPos == 0 || !IsAlNum(sc.chPrev))) {
char keyword[50];
memset(keyword, '\0', 50);
for(
int scanPosition = 0;
scanPosition < 50;
scanPosition++) {
char keywordChar = static_cast<char>(
tolower(styler.SafeGetCharAt(
scanPosition +
static_cast<Sci_Position>(sc.currentPos+1), ' ')));
if(IsAlpha(keywordChar)) {
keyword[scanPosition] = keywordChar;
} else {
break;
}
}
// It is a pragma
if(pragmatics.InList(keyword)) {
sc.SetState(SCE_MAGIK_PRAGMA);
}
// it is a normal keyword like _local, _self, etc.
else if(keywords.InList(keyword)) {
sc.SetState(SCE_MAGIK_KEYWORD);
}
// It is a container keyword, such as _method, _proc, etc.
else if(containers.InList(keyword)) {
sc.SetState(SCE_MAGIK_CONTAINER);
}
// It is a flow keyword, such as _for, _if, _try, etc.
else if(flow.InList(keyword)) {
sc.SetState(SCE_MAGIK_FLOW);
}
// Interpret as unknown keyword
else {
sc.SetState(SCE_MAGIK_UNKNOWN_KEYWORD);
}
}
// Symbolic expression
else if(sc.ch == ':' && !IsAlNum(sc.chPrev)) {
sc.SetState(SCE_MAGIK_SYMBOL);
bool firstTrip = true;
for(sc.Forward(); sc.More(); sc.Forward()) {
if(firstTrip && IsAlphaSym(sc.ch));
else if(!firstTrip && IsAlNumSym(sc.ch));
else if(sc.ch == '|') {
for(sc.Forward();
sc.More() && sc.ch != '|';
sc.Forward());
}
else break;
firstTrip = false;
}
sc.SetState(SCE_MAGIK_DEFAULT);
goto repeat;
}
// Identifier (label) expression
else if(sc.ch == '@') {
sc.SetState(SCE_MAGIK_IDENTIFIER);
bool firstTrip = true;
for(sc.Forward(); sc.More(); sc.Forward()) {
if(firstTrip && IsAlphaCore(sc.ch)) {
firstTrip = false;
}
else if(!firstTrip && IsAlpha(sc.ch));
else break;
}
sc.SetState(SCE_MAGIK_DEFAULT);
goto repeat;
}
// Start of a character
else if(sc.ch == '%') {
sc.SetState(SCE_MAGIK_CHARACTER);
sc.Forward();
char keyword[50];
memset(keyword, '\0', 50);
for(
int scanPosition = 0;
scanPosition < 50;
scanPosition++) {
char keywordChar = static_cast<char>(
tolower(styler.SafeGetCharAt(
scanPosition +
static_cast<int>(sc.currentPos), ' ')));
if(IsAlpha(keywordChar)) {
keyword[scanPosition] = keywordChar;
} else {
break;
}
}
if(characters.InList(keyword)) {
sc.Forward(static_cast<int>(strlen(keyword)));
} else {
sc.Forward();
}
sc.SetState(SCE_MAGIK_DEFAULT);
goto repeat;
}
// Operators
else if(
sc.ch == '>' ||
sc.ch == '<' ||
sc.ch == '.' ||
sc.ch == ',' ||
sc.ch == '+' ||
sc.ch == '-' ||
sc.ch == '/' ||
sc.ch == '*' ||
sc.ch == '~' ||
sc.ch == '$' ||
sc.ch == '=') {
sc.SetState(SCE_MAGIK_OPERATOR);
}
// Braces
else if(sc.ch == '(' || sc.ch == ')') {
sc.SetState(SCE_MAGIK_BRACE_BLOCK);
}
// Brackets
else if(sc.ch == '{' || sc.ch == '}') {
sc.SetState(SCE_MAGIK_BRACKET_BLOCK);
}
// Square Brackets
else if(sc.ch == '[' || sc.ch == ']') {
sc.SetState(SCE_MAGIK_SQBRACKET_BLOCK);
}
}
// It is an operator
else if(
sc.state == SCE_MAGIK_OPERATOR ||
sc.state == SCE_MAGIK_BRACE_BLOCK ||
sc.state == SCE_MAGIK_BRACKET_BLOCK ||
sc.state == SCE_MAGIK_SQBRACKET_BLOCK) {
sc.SetState(SCE_MAGIK_DEFAULT);
goto repeat;
}
// It is the pragma state
else if(sc.state == SCE_MAGIK_PRAGMA) {
if(!IsAlpha(sc.ch)) {
sc.SetState(SCE_MAGIK_DEFAULT);
goto repeat;
}
}
// It is the keyword state
else if(
sc.state == SCE_MAGIK_KEYWORD ||
sc.state == SCE_MAGIK_CONTAINER ||
sc.state == SCE_MAGIK_FLOW ||
sc.state == SCE_MAGIK_UNKNOWN_KEYWORD) {
if(!IsAlpha(sc.ch)) {
sc.SetState(SCE_MAGIK_DEFAULT);
goto repeat;
}
}
}
sc.Complete();
}
/**
* The word list description
*/
static const char * const magikWordListDesc[] = {
"Accessors (local, global, self, super, thisthread)",
"Pragmatic (pragma, private)",
"Containers (method, block, proc)",
"Flow (if, then, elif, else)",
"Characters (space, tab, newline, return)",
"Fold Containers (method, proc, block, if, loop)",
0};
/**
* This function detects keywords which are able to have a body. Note that it
* uses the Fold Containers word description, not the containers description. It
* only works when the style at that particular position is set on Containers
* or Flow (number 3 or 4).
*
* \param keywordslist The list of keywords that are scanned, they should only
* contain the start keywords, not the end keywords
* \param keyword The actual keyword
* \return 1 if it is a folding start-keyword, -1 if it is a folding end-keyword
* 0 otherwise
*/
static inline int IsFoldingContainer(WordList &keywordslist, char * keyword) {
if(
strlen(keyword) > 3 &&
keyword[0] == 'e' && keyword[1] == 'n' && keyword[2] == 'd') {
if (keywordslist.InList(keyword + 3)) {
return -1;
}
} else {
if(keywordslist.InList(keyword)) {
return 1;
}
}
return 0;
}
/**
* The folding function
*
* \param startPos Where to start scanning
* \param length Where to scan to
* \param keywordslists The keywordslists, currently, number 5 is used
* \param styler The styler
*/
static void FoldMagikDoc(Sci_PositionU startPos, Sci_Position length, int,
WordList *keywordslists[], Accessor &styler) {
bool compact = styler.GetPropertyInt("fold.compact") != 0;
WordList &foldingElements = *keywordslists[5];
Sci_Position endPos = startPos + length;
Sci_Position line = styler.GetLine(startPos);
int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK;
int flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
for(
Sci_Position currentPos = startPos;
currentPos < endPos;
currentPos++) {
char currentState = styler.StyleAt(currentPos);
char c = styler.SafeGetCharAt(currentPos, ' ');
Sci_Position prevLine = styler.GetLine(currentPos - 1);
line = styler.GetLine(currentPos);
// Default situation
if(prevLine < line) {
styler.SetLevel(line, (level|flags) & ~SC_FOLDLEVELHEADERFLAG);
flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
}
if(
(
currentState == SCE_MAGIK_CONTAINER ||
currentState == SCE_MAGIK_FLOW
) &&
c == '_') {
char keyword[50];
memset(keyword, '\0', 50);
for(
int scanPosition = 0;
scanPosition < 50;
scanPosition++) {
char keywordChar = static_cast<char>(
tolower(styler.SafeGetCharAt(
scanPosition +
currentPos + 1, ' ')));
if(IsAlpha(keywordChar)) {
keyword[scanPosition] = keywordChar;
} else {
break;
}
}
if(IsFoldingContainer(foldingElements, keyword) > 0) {
styler.SetLevel(
line,
styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
level++;
} else if(IsFoldingContainer(foldingElements, keyword) < 0) {
styler.SetLevel(line, styler.LevelAt(line));
level--;
}
}
if(
compact && (
currentState == SCE_MAGIK_BRACE_BLOCK ||
currentState == SCE_MAGIK_BRACKET_BLOCK ||
currentState == SCE_MAGIK_SQBRACKET_BLOCK)) {
if(c == '{' || c == '[' || c == '(') {
styler.SetLevel(
line,
styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
level++;
} else if(c == '}' || c == ']' || c == ')') {
styler.SetLevel(line, styler.LevelAt(line));
level--;
}
}
}
}
/**
* Injecting the module
*/
LexerModule lmMagikSF(
SCLEX_MAGIK, ColouriseMagikDoc, "magiksf", FoldMagikDoc, magikWordListDesc);

View File

@ -0,0 +1,143 @@
// Scintilla source code edit control
/** @file LexMake.cxx
** Lexer for make files.
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cstdarg>
#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;
static inline bool AtEOL(Accessor &styler, Sci_PositionU i) {
return (styler[i] == '\n') ||
((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n'));
}
static void ColouriseMakeLine(
const std::string &lineBuffer,
Sci_PositionU startLine,
Sci_PositionU endPos,
Accessor &styler) {
const Sci_PositionU lengthLine = lineBuffer.length();
Sci_PositionU i = 0;
Sci_Position lastNonSpace = -1;
unsigned int state = SCE_MAKE_DEFAULT;
bool bSpecial = false;
// check for a tab character in column 0 indicating a command
bool bCommand = false;
if ((lengthLine > 0) && (lineBuffer[0] == '\t'))
bCommand = true;
// Skip initial spaces
while ((i < lengthLine) && isspacechar(lineBuffer[i])) {
i++;
}
if (i < lengthLine) {
if (lineBuffer[i] == '#') { // Comment
styler.ColourTo(endPos, SCE_MAKE_COMMENT);
return;
}
if (lineBuffer[i] == '!') { // Special directive
styler.ColourTo(endPos, SCE_MAKE_PREPROCESSOR);
return;
}
}
int varCount = 0;
while (i < lengthLine) {
if (((i + 1) < lengthLine) && (lineBuffer[i] == '$' && lineBuffer[i + 1] == '(')) {
styler.ColourTo(startLine + i - 1, state);
state = SCE_MAKE_IDENTIFIER;
varCount++;
} else if (state == SCE_MAKE_IDENTIFIER && lineBuffer[i] == ')') {
if (--varCount == 0) {
styler.ColourTo(startLine + i, state);
state = SCE_MAKE_DEFAULT;
}
}
// skip identifier and target styling if this is a command line
if (!bSpecial && !bCommand) {
if (lineBuffer[i] == ':') {
if (((i + 1) < lengthLine) && (lineBuffer[i + 1] == '=')) {
// it's a ':=', so style as an identifier
if (lastNonSpace >= 0)
styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_IDENTIFIER);
styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);
styler.ColourTo(startLine + i + 1, SCE_MAKE_OPERATOR);
} else {
// We should check that no colouring was made since the beginning of the line,
// to avoid colouring stuff like /OUT:file
if (lastNonSpace >= 0)
styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_TARGET);
styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);
styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR);
}
bSpecial = true; // Only react to the first ':' of the line
state = SCE_MAKE_DEFAULT;
} else if (lineBuffer[i] == '=') {
if (lastNonSpace >= 0)
styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_IDENTIFIER);
styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);
styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR);
bSpecial = true; // Only react to the first '=' of the line
state = SCE_MAKE_DEFAULT;
}
}
if (!isspacechar(lineBuffer[i])) {
lastNonSpace = i;
}
i++;
}
if (state == SCE_MAKE_IDENTIFIER) {
styler.ColourTo(endPos, SCE_MAKE_IDEOL); // Error, variable reference not ended
} else {
styler.ColourTo(endPos, SCE_MAKE_DEFAULT);
}
}
static void ColouriseMakeDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
std::string lineBuffer;
styler.StartAt(startPos);
styler.StartSegment(startPos);
Sci_PositionU startLine = startPos;
for (Sci_PositionU i = startPos; i < startPos + length; i++) {
lineBuffer.push_back(styler[i]);
if (AtEOL(styler, i)) {
// End of line (or of line buffer) met, colourise it
ColouriseMakeLine(lineBuffer, startLine, i, styler);
lineBuffer.clear();
startLine = i + 1;
}
}
if (!lineBuffer.empty()) { // Last line does not have ending characters
ColouriseMakeLine(lineBuffer, startLine, startPos + length - 1, styler);
}
}
static const char *const emptyWordListDesc[] = {
nullptr
};
LexerModule lmMake(SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile", nullptr, emptyWordListDesc);

View File

@ -0,0 +1,486 @@
/******************************************************************
* LexMarkdown.cxx
*
* A simple Markdown lexer for scintilla.
*
* Includes highlighting for some extra features from the
* Pandoc implementation; strikeout, using '#.' as a default
* ordered list item marker, and delimited code blocks.
*
* Limitations:
*
* Standard indented code blocks are not highlighted at all,
* as it would conflict with other indentation schemes. Use
* delimited code blocks for blanket highlighting of an
* entire code block. Embedded HTML is not highlighted either.
* Blanket HTML highlighting has issues, because some Markdown
* implementations allow Markdown markup inside of the HTML. Also,
* there is a following blank line issue that can't be ignored,
* explained in the next paragraph. Embedded HTML and code
* blocks would be better supported with language specific
* highlighting.
*
* The highlighting aims to accurately reflect correct syntax,
* but a few restrictions are relaxed. Delimited code blocks are
* highlighted, even if the line following the code block is not blank.
* Requiring a blank line after a block, breaks the highlighting
* in certain cases, because of the way Scintilla ends up calling
* the lexer.
*
* Written by Jon Strait - jstrait@moonloop.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 <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;
namespace {
constexpr bool IsNewline(const int ch) {
// sc.GetRelative(i) returns '\0' if out of range
return (ch == '\n' || ch == '\r' || ch == '\0');
}
}
// True if can follow ch down to the end with possibly trailing whitespace
// Does not set the state SCE_MARKDOWN_LINE_BEGIN as to allow further processing
static bool FollowToLineEnd(const int ch, const int state, const Sci_PositionU endPos, StyleContext &sc) {
Sci_Position i = 0;
while (sc.GetRelative(++i) == ch)
;
// Skip over whitespace
while (IsASpaceOrTab(sc.GetRelative(i)) && sc.currentPos + i < endPos)
++i;
if (IsNewline(sc.GetRelative(i)) || sc.currentPos + i == endPos) {
sc.SetState(state);
sc.Forward(i);
return true;
}
else return false;
}
// Set the state on text section from current to length characters,
// then set the rest until the newline to default, except for any characters matching token
static void SetStateAndZoom(const int state, const Sci_Position length, const int token, StyleContext &sc) {
sc.SetState(state);
sc.Forward(length);
sc.SetState(SCE_MARKDOWN_DEFAULT);
sc.Forward();
bool started = false;
while (sc.More() && !IsNewline(sc.ch)) {
if (sc.ch == token && !started) {
sc.SetState(state);
started = true;
}
else if (sc.ch != token) {
sc.SetState(SCE_MARKDOWN_DEFAULT);
started = false;
}
sc.Forward();
}
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
}
// Does the previous line have more than spaces and tabs?
static bool HasPrevLineContent(StyleContext &sc) {
Sci_Position i = 0;
// Go back to the previous newline
while ((--i + (Sci_Position)sc.currentPos) >= 0 && !IsNewline(sc.GetRelative(i)))
;
while ((--i + (Sci_Position)sc.currentPos) >= 0) {
const int ch = sc.GetRelative(i);
if (ch == '\n')
break;
if (!((ch == '\r' || IsASpaceOrTab(ch))))
return true;
}
return false;
}
static bool AtTermStart(StyleContext &sc) {
return sc.currentPos == 0 || sc.chPrev == 0 || isspacechar(sc.chPrev);
}
static bool IsCompleteStyleRegion(StyleContext &sc, const char *token) {
bool found = false;
const size_t start = strlen(token);
Sci_Position i = static_cast<Sci_Position>(start);
while (!IsNewline(sc.GetRelative(i))) {
// make sure an empty pair of single-char tokens doesn't match
// with a longer token: {*}{*} != {**}
if (sc.GetRelative(i) == *token && sc.GetRelative(i - 1) != *token) {
found = start > 1U ? sc.GetRelative(i + 1) == token[1] : true;
break;
}
i++;
}
return AtTermStart(sc) && found;
}
static bool IsValidHrule(const Sci_PositionU endPos, StyleContext &sc) {
int count = 1;
Sci_Position i = 0;
for (;;) {
++i;
int c = sc.GetRelative(i);
if (c == sc.ch)
++count;
// hit a terminating character
else if (!IsASpaceOrTab(c) || sc.currentPos + i == endPos) {
// Are we a valid HRULE
if ((IsNewline(c) || sc.currentPos + i == endPos) &&
count >= 3 && !HasPrevLineContent(sc)) {
sc.SetState(SCE_MARKDOWN_HRULE);
sc.Forward(i);
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
return true;
}
else {
sc.SetState(SCE_MARKDOWN_DEFAULT);
return false;
}
}
}
}
static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList **, Accessor &styler) {
Sci_PositionU endPos = startPos + length;
int precharCount = 0;
bool isLinkNameDetecting = false;
// Don't advance on a new loop iteration and retry at the same position.
// Useful in the corner case of having to start at the beginning file position
// in the default state.
bool freezeCursor = false;
// property lexer.markdown.header.eolfill
// Set to 1 to highlight all ATX header text.
bool headerEOLFill = styler.GetPropertyInt("lexer.markdown.header.eolfill", 0) == 1;
StyleContext sc(startPos, static_cast<Sci_PositionU>(length), initStyle, styler);
while (sc.More()) {
// Skip past escaped characters
if (sc.ch == '\\') {
sc.Forward();
continue;
}
// A blockquotes resets the line semantics
if (sc.state == SCE_MARKDOWN_BLOCKQUOTE)
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
// Conditional state-based actions
if (sc.state == SCE_MARKDOWN_CODE2) {
if (sc.Match("``")) {
const int closingSpan = (sc.GetRelative(2) == '`') ? 3 : 2;
sc.Forward(closingSpan);
sc.SetState(SCE_MARKDOWN_DEFAULT);
}
}
else if (sc.state == SCE_MARKDOWN_CODE) {
if (sc.ch == '`' && sc.chPrev != ' ')
sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
}
/* De-activated because it gets in the way of other valid indentation
* schemes, for example multiple paragraphs inside a list item.
// Code block
else if (sc.state == SCE_MARKDOWN_CODEBK) {
bool d = true;
if (IsNewline(sc.ch)) {
if (sc.chNext != '\t') {
for (int c = 1; c < 5; ++c) {
if (sc.GetRelative(c) != ' ')
d = false;
}
}
}
else if (sc.atLineStart) {
if (sc.ch != '\t' ) {
for (int i = 0; i < 4; ++i) {
if (sc.GetRelative(i) != ' ')
d = false;
}
}
}
if (!d)
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
}
*/
// Strong
else if (sc.state == SCE_MARKDOWN_STRONG1) {
if ((sc.Match("**") && sc.chPrev != ' ') || IsNewline(sc.GetRelative(2))) {
sc.Forward(2);
sc.SetState(SCE_MARKDOWN_DEFAULT);
}
}
else if (sc.state == SCE_MARKDOWN_STRONG2) {
if ((sc.Match("__") && sc.chPrev != ' ') || IsNewline(sc.GetRelative(2))) {
sc.Forward(2);
sc.SetState(SCE_MARKDOWN_DEFAULT);
}
}
// Emphasis
else if (sc.state == SCE_MARKDOWN_EM1) {
if ((sc.ch == '*' && sc.chPrev != ' ') || IsNewline(sc.chNext))
sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
}
else if (sc.state == SCE_MARKDOWN_EM2) {
if ((sc.ch == '_' && sc.chPrev != ' ') || IsNewline(sc.chNext))
sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
}
else if (sc.state == SCE_MARKDOWN_CODEBK) {
if (sc.atLineStart && sc.Match("~~~")) {
Sci_Position i = 1;
while (!IsNewline(sc.GetRelative(i)) && sc.currentPos + i < endPos)
i++;
sc.Forward(i);
sc.SetState(SCE_MARKDOWN_DEFAULT);
}
}
else if (sc.state == SCE_MARKDOWN_STRIKEOUT) {
if ((sc.Match("~~") && sc.chPrev != ' ') || IsNewline(sc.GetRelative(2))) {
sc.Forward(2);
sc.SetState(SCE_MARKDOWN_DEFAULT);
}
}
else if (sc.state == SCE_MARKDOWN_LINE_BEGIN) {
// Header
if (sc.Match("######")) {
if (headerEOLFill)
sc.SetState(SCE_MARKDOWN_HEADER6);
else
SetStateAndZoom(SCE_MARKDOWN_HEADER6, 6, '#', sc);
}
else if (sc.Match("#####")) {
if (headerEOLFill)
sc.SetState(SCE_MARKDOWN_HEADER5);
else
SetStateAndZoom(SCE_MARKDOWN_HEADER5, 5, '#', sc);
}
else if (sc.Match("####")) {
if (headerEOLFill)
sc.SetState(SCE_MARKDOWN_HEADER4);
else
SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc);
}
else if (sc.Match("###")) {
if (headerEOLFill)
sc.SetState(SCE_MARKDOWN_HEADER3);
else
SetStateAndZoom(SCE_MARKDOWN_HEADER3, 3, '#', sc);
}
else if (sc.Match("##")) {
if (headerEOLFill)
sc.SetState(SCE_MARKDOWN_HEADER2);
else
SetStateAndZoom(SCE_MARKDOWN_HEADER2, 2, '#', sc);
}
else if (sc.Match("#")) {
// Catch the special case of an unordered list
if (sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) {
precharCount = 0;
sc.SetState(SCE_MARKDOWN_PRECHAR);
}
else if (headerEOLFill) {
sc.SetState(SCE_MARKDOWN_HEADER1);
}
else
SetStateAndZoom(SCE_MARKDOWN_HEADER1, 1, '#', sc);
}
// Code block
else if (sc.Match("~~~")) {
if (!HasPrevLineContent(sc))
sc.SetState(SCE_MARKDOWN_CODEBK);
else
sc.SetState(SCE_MARKDOWN_DEFAULT);
}
else if (sc.ch == '=') {
if (HasPrevLineContent(sc) && FollowToLineEnd('=', SCE_MARKDOWN_HEADER1, endPos, sc)) {
if (!headerEOLFill)
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
}
else
sc.SetState(SCE_MARKDOWN_DEFAULT);
}
else if (sc.ch == '-') {
if (HasPrevLineContent(sc) && FollowToLineEnd('-', SCE_MARKDOWN_HEADER2, endPos, sc)) {
if (!headerEOLFill)
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
}
else {
precharCount = 0;
sc.SetState(SCE_MARKDOWN_PRECHAR);
}
}
else if (IsNewline(sc.ch))
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
else {
precharCount = 0;
sc.SetState(SCE_MARKDOWN_PRECHAR);
}
}
// The header lasts until the newline
else if (sc.state == SCE_MARKDOWN_HEADER1 || sc.state == SCE_MARKDOWN_HEADER2 ||
sc.state == SCE_MARKDOWN_HEADER3 || sc.state == SCE_MARKDOWN_HEADER4 ||
sc.state == SCE_MARKDOWN_HEADER5 || sc.state == SCE_MARKDOWN_HEADER6) {
if (headerEOLFill) {
if (sc.atLineStart) {
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
freezeCursor = true;
}
}
else if (IsNewline(sc.ch))
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
}
// New state only within the initial whitespace
if (sc.state == SCE_MARKDOWN_PRECHAR) {
// Blockquote
if (sc.ch == '>' && precharCount < 5)
sc.SetState(SCE_MARKDOWN_BLOCKQUOTE);
/*
// Begin of code block
else if (!HasPrevLineContent(sc) && (sc.chPrev == '\t' || precharCount >= 4))
sc.SetState(SCE_MARKDOWN_CODEBK);
*/
// HRule - Total of three or more hyphens, asterisks, or underscores
// on a line by themselves
else if ((sc.ch == '-' || sc.ch == '*' || sc.ch == '_') && IsValidHrule(endPos, sc))
;
// Unordered list
else if ((sc.ch == '-' || sc.ch == '*' || sc.ch == '+') && IsASpaceOrTab(sc.chNext)) {
sc.SetState(SCE_MARKDOWN_ULIST_ITEM);
sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
}
// Ordered list
else if (IsADigit(sc.ch)) {
int digitCount = 0;
while (IsADigit(sc.GetRelative(++digitCount)))
;
if (sc.GetRelative(digitCount) == '.' &&
IsASpaceOrTab(sc.GetRelative(digitCount + 1))) {
sc.SetState(SCE_MARKDOWN_OLIST_ITEM);
sc.Forward(digitCount + 1);
sc.SetState(SCE_MARKDOWN_DEFAULT);
} else {
// a textual number at the margin should be plain text
sc.SetState(SCE_MARKDOWN_DEFAULT);
}
}
// Alternate Ordered list
else if (sc.ch == '#' && sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) {
sc.SetState(SCE_MARKDOWN_OLIST_ITEM);
sc.Forward(2);
sc.SetState(SCE_MARKDOWN_DEFAULT);
}
else if (sc.ch != ' ' || precharCount > 2)
sc.SetState(SCE_MARKDOWN_DEFAULT);
else
++precharCount;
}
// Any link
if (sc.state == SCE_MARKDOWN_LINK) {
if (sc.Match("](") && sc.GetRelative(-1) != '\\') {
sc.Forward(2);
isLinkNameDetecting = true;
}
else if (sc.Match("]:") && sc.GetRelative(-1) != '\\') {
sc.Forward(2);
sc.SetState(SCE_MARKDOWN_DEFAULT);
}
else if (!isLinkNameDetecting && sc.ch == ']' && sc.GetRelative(-1) != '\\') {
sc.Forward();
sc.SetState(SCE_MARKDOWN_DEFAULT);
}
else if (isLinkNameDetecting && sc.ch == ')' && sc.GetRelative(-1) != '\\') {
sc.Forward();
sc.SetState(SCE_MARKDOWN_DEFAULT);
isLinkNameDetecting = false;
}
}
// New state anywhere in doc
if (sc.state == SCE_MARKDOWN_DEFAULT) {
if (sc.atLineStart && sc.ch == '#') {
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
freezeCursor = true;
}
// Links and Images
if (sc.Match("![")) {
sc.SetState(SCE_MARKDOWN_LINK);
sc.Forward(1);
}
else if (sc.ch == '[' && sc.GetRelative(-1) != '\\') {
sc.SetState(SCE_MARKDOWN_LINK);
}
// Code - also a special case for alternate inside spacing
else if (sc.Match("``") && sc.GetRelative(3) != ' ' && AtTermStart(sc)) {
const int openingSpan = (sc.GetRelative(2) == '`') ? 2 : 1;
sc.SetState(SCE_MARKDOWN_CODE2);
sc.Forward(openingSpan);
}
else if (sc.ch == '`' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "`")) {
sc.SetState(SCE_MARKDOWN_CODE);
}
// Strong
else if (sc.Match("**") && sc.GetRelative(2) != ' ' && IsCompleteStyleRegion(sc, "**")) {
sc.SetState(SCE_MARKDOWN_STRONG1);
sc.Forward();
}
else if (sc.Match("__") && sc.GetRelative(2) != ' ' && IsCompleteStyleRegion(sc, "__")) {
sc.SetState(SCE_MARKDOWN_STRONG2);
sc.Forward();
}
// Emphasis
else if (sc.ch == '*' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "*")) {
sc.SetState(SCE_MARKDOWN_EM1);
}
else if (sc.ch == '_' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "_")) {
sc.SetState(SCE_MARKDOWN_EM2);
}
// Strikeout
else if (sc.Match("~~") && !(sc.GetRelative(2) == '~' || sc.GetRelative(2) == ' ') &&
IsCompleteStyleRegion(sc, "~~")) {
sc.SetState(SCE_MARKDOWN_STRIKEOUT);
sc.Forward();
}
// Beginning of line
else if (IsNewline(sc.ch)) {
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
}
}
// Advance if not holding back the cursor for this iteration.
if (!freezeCursor)
sc.Forward();
freezeCursor = false;
}
sc.Complete();
}
LexerModule lmMarkdown(SCLEX_MARKDOWN, ColorizeMarkdownDoc, "markdown");

View File

@ -0,0 +1,528 @@
// Scintilla source code edit control
// Encoding: UTF-8
/** @file LexMatlab.cxx
** Lexer for Matlab.
** Written by José Fonseca
**
** Changes by Christoph Dalitz 2003/12/04:
** - added support for Octave
** - Strings can now be included both in single or double quotes
**
** Changes by John Donoghue 2012/04/02
** - added block comment (and nested block comments)
** - added ... displayed as a comment
** - removed unused IsAWord functions
** - added some comments
**
** Changes by John Donoghue 2014/08/01
** - fix allowed transpose ' after {} operator
**
** Changes by John Donoghue 2016/11/15
** - update matlab code folding
**
** Changes by John Donoghue 2017/01/18
** - update matlab block comment detection
**
** Changes by Andrey Smolyakov 2022/04/15
** - add support for "arguments" block and class definition syntax
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// 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;
static bool IsMatlabCommentChar(int c) {
return (c == '%') ;
}
static bool IsOctaveCommentChar(int c) {
return (c == '%' || c == '#') ;
}
static inline int LowerCase(int c) {
if (c >= 'A' && c <= 'Z')
return 'a' + c - 'A';
return c;
}
static int CheckKeywordFoldPoint(char *str) {
if (strcmp ("if", str) == 0 ||
strcmp ("for", str) == 0 ||
strcmp ("switch", str) == 0 ||
strcmp ("while", str) == 0 ||
strcmp ("try", str) == 0 ||
strcmp ("do", str) == 0 ||
strcmp ("parfor", str) == 0 ||
strcmp ("classdef", str) == 0 ||
strcmp ("spmd", str) == 0 ||
strcmp ("arguments", str) == 0 ||
strcmp ("methods", str) == 0 ||
strcmp ("properties", str) == 0 ||
strcmp ("events", str) == 0 ||
strcmp ("function", str) == 0)
return 1;
if (strncmp("end", str, 3) == 0 ||
strcmp("until", str) == 0)
return -1;
return 0;
}
static bool IsSpaceToEOL(Sci_Position startPos, Accessor &styler) {
Sci_Position line = styler.GetLine(startPos);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = startPos; i < eol_pos; i++) {
char ch = styler[i];
if(!IsASpace(ch)) return false;
}
return true;
}
#define MATLAB_STATE_FOLD_LVL_OFFSET 8
#define MATLAB_STATE_FOLD_LVL_MASK (0xFF00)
#define MATLAB_STATE_FLAGS_OFFSET 16
#define MATLAB_STATE_COMM_DEPTH_OFFSET 0
#define MATLAB_STATE_COMM_DEPTH_MASK (0xFF)
#define MATLAB_STATE_EXPECTING_ARG_BLOCK (1 << MATLAB_STATE_FLAGS_OFFSET)
#define MATLAB_STATE_IN_CLASS_SCOPE (1 <<(MATLAB_STATE_FLAGS_OFFSET+1))
#define MATLAB_STATE_IN_ARGUMENTS_SCOPE (1 <<(MATLAB_STATE_FLAGS_OFFSET+2))
static int ComposeLineState(int commentDepth,
int foldingLevel,
int expectingArgumentsBlock,
int inClassScope,
int inArgumentsScope) {
return ((commentDepth << MATLAB_STATE_COMM_DEPTH_OFFSET)
& MATLAB_STATE_COMM_DEPTH_MASK) |
((foldingLevel << MATLAB_STATE_FOLD_LVL_OFFSET)
& MATLAB_STATE_FOLD_LVL_MASK) |
(expectingArgumentsBlock
& MATLAB_STATE_EXPECTING_ARG_BLOCK) |
(inClassScope
& MATLAB_STATE_IN_CLASS_SCOPE) |
(inArgumentsScope
& MATLAB_STATE_IN_ARGUMENTS_SCOPE);
}
static void ColouriseMatlabOctaveDoc(
Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler,
bool (*IsCommentChar)(int),
bool ismatlab) {
WordList &keywords = *keywordlists[0];
styler.StartAt(startPos);
// boolean for when the ' is allowed to be transpose vs the start/end
// of a string
bool transpose = false;
// count of brackets as boolean for when end could be an operator not a keyword
int allow_end_op = 0;
// approximate position of first non space character in a line
int nonSpaceColumn = -1;
// approximate column position of the current character in a line
int column = 0;
// This line contains a function declaration
bool funcDeclarationLine = false;
// We've just seen "function" keyword, so now we may expect the "arguments"
// keyword opening the corresponding code block
int expectingArgumentsBlock = 0;
// We saw "arguments" keyword, but not the closing "end"
int inArgumentsScope = 0;
// Current line's folding level
int foldingLevel = 0;
// Current line in in class scope
int inClassScope = 0;
// use the line state of each line to store the block comment depth
Sci_Position curLine = styler.GetLine(startPos);
int commentDepth = 0;
// Restore the previous line's state, if there was such a line
if (curLine > 0) {
int prevState = styler.GetLineState(curLine-1);
commentDepth = (prevState & MATLAB_STATE_COMM_DEPTH_MASK)
>> MATLAB_STATE_COMM_DEPTH_OFFSET;
foldingLevel = (prevState & MATLAB_STATE_FOLD_LVL_MASK)
>> MATLAB_STATE_FOLD_LVL_OFFSET;
expectingArgumentsBlock = prevState & MATLAB_STATE_EXPECTING_ARG_BLOCK;
inClassScope = prevState & MATLAB_STATE_IN_CLASS_SCOPE;
inArgumentsScope = prevState & MATLAB_STATE_IN_ARGUMENTS_SCOPE;
}
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward(), column++) {
if(sc.atLineStart) {
// set the line state to the current commentDepth
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, ComposeLineState(
commentDepth, foldingLevel, expectingArgumentsBlock, inClassScope, inArgumentsScope));
// reset the column to 0, nonSpace to -1 (not set)
column = 0;
nonSpaceColumn = -1;
// Reset the flag
funcDeclarationLine = false;
}
// Semicolon ends function declaration
// This condition is for one line functions support
if (sc.chPrev == ';') {
funcDeclarationLine = false;
}
// Only comments allowed between the function declaration and the
// arguments code block
if (expectingArgumentsBlock && !(funcDeclarationLine || inArgumentsScope)) {
if ((sc.state != SCE_MATLAB_KEYWORD) &&
(sc.state != SCE_MATLAB_COMMENT) &&
(sc.state != SCE_MATLAB_DEFAULT) &&
!(sc.state == SCE_MATLAB_OPERATOR && sc.chPrev == ';')) {
expectingArgumentsBlock = 0;
styler.SetLineState(curLine, ComposeLineState(
commentDepth, foldingLevel, expectingArgumentsBlock, inClassScope, inArgumentsScope));
}
}
// We've just left the class scope
if ((foldingLevel ==0) && inClassScope) {
inClassScope = 0;
}
// save the column position of first non space character in a line
if((nonSpaceColumn == -1) && (! IsASpace(sc.ch))) {
nonSpaceColumn = column;
}
// check for end of states
if (sc.state == SCE_MATLAB_OPERATOR) {
if (sc.chPrev == '.') {
if (sc.ch == '*' || sc.ch == '/' || sc.ch == '\\' || sc.ch == '^') {
sc.ForwardSetState(SCE_MATLAB_DEFAULT);
transpose = false;
} else if (sc.ch == '\'') {
sc.ForwardSetState(SCE_MATLAB_DEFAULT);
transpose = true;
} else if(sc.ch == '.' && sc.chNext == '.') {
// we werent an operator, but a '...'
sc.ChangeState(SCE_MATLAB_COMMENT);
transpose = false;
} else {
sc.SetState(SCE_MATLAB_DEFAULT);
}
} else {
sc.SetState(SCE_MATLAB_DEFAULT);
}
} else if (sc.state == SCE_MATLAB_KEYWORD) {
if (!isalnum(sc.ch) && sc.ch != '_') {
char s[100];
sc.GetCurrent(s, sizeof(s));
bool notKeyword = false;
transpose = false;
if (keywords.InList(s)) {
expectingArgumentsBlock = (funcDeclarationLine || inArgumentsScope) ? expectingArgumentsBlock : 0;
if (strcmp ("end", s) == 0 && allow_end_op) {
sc.ChangeState(SCE_MATLAB_NUMBER);
notKeyword = true;
} else if (strcmp("end", s) == 0 && !allow_end_op) {
inArgumentsScope = 0;
} else if (strcmp("function", s) == 0) {
// Need this flag to handle "arguments" block correctly
funcDeclarationLine = true;
expectingArgumentsBlock = ismatlab ? MATLAB_STATE_EXPECTING_ARG_BLOCK : 0;
} else if (strcmp("classdef", s) == 0) {
// Need this flag to process "events", "methods" and "properties" blocks
inClassScope = MATLAB_STATE_IN_CLASS_SCOPE;
}
} else {
// "arguments" is a keyword here, despite not being in the keywords list
if (expectingArgumentsBlock && !(funcDeclarationLine || inArgumentsScope) && (strcmp("arguments", s) == 0)) {
// We've entered an "arguments" block
inArgumentsScope = MATLAB_STATE_IN_ARGUMENTS_SCOPE;
} else {
// Found an identifier or a keyword after the function declaration
// No need to wait for the arguments block anymore
expectingArgumentsBlock = (funcDeclarationLine || inArgumentsScope) ? expectingArgumentsBlock : 0;
// "properties", "methods" and "events" are not keywords if they're declared
// inside some function in methods block
// To avoid tracking possible nested functions scopes, lexer considers everything
// beyond level 2 of folding to be in a scope of some function declared in the
// methods block. It is ok for the valid syntax: classes can only be declared in
// a separate file, function - only in methods block. However, in case of the invalid
// syntax lexer may erroneously ignore a keyword.
if (!((inClassScope) && (foldingLevel <= 2) && (
strcmp("properties", s) == 0 ||
strcmp("methods", s) == 0 ||
strcmp("events", s) == 0 ))) {
sc.ChangeState(SCE_MATLAB_IDENTIFIER);
transpose = true;
notKeyword = true;
}
}
}
sc.SetState(SCE_MATLAB_DEFAULT);
if (!notKeyword) {
foldingLevel += CheckKeywordFoldPoint(s);
}
}
styler.SetLineState(curLine, ComposeLineState(
commentDepth, foldingLevel, expectingArgumentsBlock, inClassScope, inArgumentsScope));
} else if (sc.state == SCE_MATLAB_NUMBER) {
if (!isdigit(sc.ch) && sc.ch != '.'
&& !(sc.ch == 'e' || sc.ch == 'E')
&& !((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E'))
&& !(((sc.ch == 'x' || sc.ch == 'X') && sc.chPrev == '0') || (sc.ch >= 'a' && sc.ch <= 'f') || (sc.ch >= 'A' && sc.ch <= 'F'))
&& !(sc.ch == 's' || sc.ch == 'S' || sc.ch == 'u' || sc.ch == 'U')
&& !(sc.ch == 'i' || sc.ch == 'I' || sc.ch == 'j' || sc.ch == 'J')
&& !(sc.ch == '_')) {
sc.SetState(SCE_MATLAB_DEFAULT);
transpose = true;
}
} else if (sc.state == SCE_MATLAB_STRING) {
if (sc.ch == '\'') {
if (sc.chNext == '\'') {
sc.Forward();
} else {
sc.ForwardSetState(SCE_MATLAB_DEFAULT);
}
} else if (sc.MatchLineEnd()) {
sc.SetState(SCE_MATLAB_DEFAULT);
}
} else if (sc.state == SCE_MATLAB_DOUBLEQUOTESTRING) {
if (sc.ch == '\\' && !ismatlab) {
sc.Forward(); // skip escape sequence, new line and others after backlash
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_MATLAB_DEFAULT);
} else if (sc.MatchLineEnd()) {
sc.SetState(SCE_MATLAB_DEFAULT);
}
} else if (sc.state == SCE_MATLAB_COMMAND) {
if (sc.atLineEnd) {
sc.SetState(SCE_MATLAB_DEFAULT);
transpose = false;
}
} else if (sc.state == SCE_MATLAB_COMMENT) {
// end or start of a nested a block comment?
if( IsCommentChar(sc.ch) && sc.chNext == '}' && nonSpaceColumn == column && IsSpaceToEOL(sc.currentPos+2, styler)) {
if(commentDepth > 0) commentDepth --;
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, ComposeLineState(
commentDepth, foldingLevel, expectingArgumentsBlock, inClassScope, inArgumentsScope));
sc.Forward();
if (commentDepth == 0) {
sc.ForwardSetState(SCE_MATLAB_DEFAULT);
transpose = false;
}
} else if( IsCommentChar(sc.ch) && sc.chNext == '{' && nonSpaceColumn == column && IsSpaceToEOL(sc.currentPos+2, styler)) {
commentDepth ++;
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, ComposeLineState(
commentDepth, foldingLevel, expectingArgumentsBlock, inClassScope, inArgumentsScope));
sc.Forward();
transpose = false;
} else if(commentDepth == 0) {
// single line comment
if (sc.atLineEnd || sc.ch == '\r' || sc.ch == '\n') {
sc.SetState(SCE_MATLAB_DEFAULT);
transpose = false;
}
}
}
// check start of a new state
if (sc.state == SCE_MATLAB_DEFAULT) {
if (IsCommentChar(sc.ch)) {
// ncrement depth if we are a block comment
if(sc.chNext == '{' && nonSpaceColumn == column) {
if(IsSpaceToEOL(sc.currentPos+2, styler)) {
commentDepth ++;
}
}
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, ComposeLineState(
commentDepth, foldingLevel, expectingArgumentsBlock, inClassScope, inArgumentsScope));
sc.SetState(SCE_MATLAB_COMMENT);
} else if (sc.ch == '!' && sc.chNext != '=' ) {
if(ismatlab) {
sc.SetState(SCE_MATLAB_COMMAND);
} else {
sc.SetState(SCE_MATLAB_OPERATOR);
}
} else if (sc.ch == '\'') {
if (transpose) {
sc.SetState(SCE_MATLAB_OPERATOR);
} else {
sc.SetState(SCE_MATLAB_STRING);
}
} else if (sc.ch == '"') {
sc.SetState(SCE_MATLAB_DOUBLEQUOTESTRING);
} else if (isdigit(sc.ch) || (sc.ch == '.' && isdigit(sc.chNext))) {
sc.SetState(SCE_MATLAB_NUMBER);
} else if (isalpha(sc.ch)) {
sc.SetState(SCE_MATLAB_KEYWORD);
} else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@' || sc.ch == '\\') {
if (sc.ch == '(' || sc.ch == '[' || sc.ch == '{') {
allow_end_op ++;
} else if ((sc.ch == ')' || sc.ch == ']' || sc.ch == '}') && (allow_end_op > 0)) {
allow_end_op --;
}
if (sc.ch == ')' || sc.ch == ']' || sc.ch == '}') {
transpose = true;
} else {
transpose = false;
}
sc.SetState(SCE_MATLAB_OPERATOR);
} else {
transpose = false;
}
}
}
sc.Complete();
}
static void ColouriseMatlabDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler) {
ColouriseMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsMatlabCommentChar, true);
}
static void ColouriseOctaveDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler) {
ColouriseMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsOctaveCommentChar, false);
}
static void FoldMatlabOctaveDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *[], Accessor &styler,
bool (*IsComment)(int ch)) {
if (styler.GetPropertyInt("fold") == 0)
return;
const bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
const bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelCurrent = SC_FOLDLEVELBASE;
if (lineCurrent > 0)
levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
int levelNext = levelCurrent;
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
int style = initStyle;
char word[100];
int wordlen = 0;
for (Sci_PositionU i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
style = styleNext;
styleNext = styler.StyleAt(i + 1);
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
// a line that starts with a comment
if (foldComment && style == SCE_MATLAB_COMMENT && IsComment(ch) && visibleChars == 0) {
// start/end of block comment
if (chNext == '{' && IsSpaceToEOL(i+2, styler))
levelNext ++;
if (chNext == '}' && IsSpaceToEOL(i+2, styler))
levelNext --;
}
// keyword
if(style == SCE_MATLAB_KEYWORD) {
word[wordlen++] = static_cast<char>(LowerCase(ch));
if (wordlen == 100) { // prevent overflow
word[0] = '\0';
wordlen = 1;
}
if (styleNext != SCE_MATLAB_KEYWORD) {
word[wordlen] = '\0';
wordlen = 0;
levelNext += CheckKeywordFoldPoint(word);
}
}
if (!IsASpace(ch))
visibleChars++;
if (atEOL || (i == endPos-1)) {
int levelUse = levelCurrent;
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;
if (atEOL && (i == static_cast<Sci_PositionU>(styler.Length() - 1))) {
// There is an empty line at end of file so give it same level and empty
styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
}
visibleChars = 0;
}
}
}
static void FoldMatlabDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler) {
FoldMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsMatlabCommentChar);
}
static void FoldOctaveDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList *keywordlists[], Accessor &styler) {
FoldMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsOctaveCommentChar);
}
static const char * const matlabWordListDesc[] = {
"Keywords",
0
};
static const char * const octaveWordListDesc[] = {
"Keywords",
0
};
LexerModule lmMatlab(SCLEX_MATLAB, ColouriseMatlabDoc, "matlab", FoldMatlabDoc, matlabWordListDesc);
LexerModule lmOctave(SCLEX_OCTAVE, ColouriseOctaveDoc, "octave", FoldOctaveDoc, octaveWordListDesc);

View File

@ -0,0 +1,225 @@
// Scintilla source code edit control
/** @file LexMaxima.cxx
** Lexer for Maxima (http://maxima.sourceforge.net).
** Written by Gunter Königsmann based on the lisp lexer by Alexey Yutkin and Neil Hodgson .
**/
// Copyright 2018 by Gunter Königsmann <wxMaxima@physikbuch.de>
// 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;
static inline bool isMaximaoperator(char ch) {
return (ch == '\'' || ch == '`' || ch == '(' ||
ch == ')' || ch == '[' || ch == ']' ||
ch == '{' || ch == '}' || ch == '!' ||
ch == '*' || ch == '/' || ch == '^' ||
ch == ',' || ch == ':' || ch == '+' ||
ch == '-');
}
static void ColouriseMaximaDoc(Sci_PositionU startPos, Sci_Position length, int lastStyle,
WordList *[],
Accessor &styler) {
styler.StartAt(startPos);
Sci_PositionU lengthDoc = startPos + length;
styler.StartSegment(startPos);
Sci_PositionU i = startPos;
// If we are in the middle of a comment we go back to its start before highlighting
if(lastStyle == SCE_MAXIMA_COMMENT)
{
while((i>0) &&
!((styler.SafeGetCharAt(i+1) == '*') && (styler.SafeGetCharAt(i) == '/')))
i--;
}
for (; i < lengthDoc; i++) {
char ch = styler.SafeGetCharAt(i);
char chNext = styler.SafeGetCharAt(i + 1);
if (styler.IsLeadByte(ch))
continue;
// Handle comments.
// Comments start with /* and end with */
if((ch == '/') && (chNext == '*'))
{
i++;i++;
chNext = styler.SafeGetCharAt(i);
for (; i < lengthDoc; i++)
{
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if((ch == '*') && (chNext == '/'))
{
i++;
i++;
break;
}
}
if(i > lengthDoc)
i = lengthDoc;
i--;
styler.ColourTo(i, SCE_MAXIMA_COMMENT);
continue;
}
// Handle Operators
if(isMaximaoperator(ch))
{
styler.ColourTo(i, SCE_MAXIMA_OPERATOR);
continue;
}
// Handle command endings.
if((ch == '$') || (ch == ';'))
{
styler.ColourTo(i, SCE_MAXIMA_COMMANDENDING);
continue;
}
// Handle numbers. Numbers always begin with a digit.
if(IsASCII(ch) && isdigit(ch))
{
i++;
for (; i < lengthDoc; i++)
{
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if(ch == '.')
continue;
// A "e" or similar can be followed by a "+" or a "-"
if(((ch == 'e') || (ch == 'b') || (ch == 'g') || (ch == 'f')) &&
((chNext == '+') || (chNext == '-')))
{
i++;
chNext = styler.SafeGetCharAt(i + 1);
continue;
}
if(!IsASCII(ch) || !(isdigit(ch) || islower(ch) || isupper(ch)))
{
i--;
break;
}
}
styler.ColourTo(i, SCE_MAXIMA_NUMBER);
continue;
}
// Handle strings
if(ch == '\"')
{
i++;
for (; i < lengthDoc; i++)
{
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if(ch == '\\')
i++;
else
{
if(ch == '\"')
break;
}
}
styler.ColourTo(i, SCE_MAXIMA_STRING);
continue;
}
// Handle keywords. Maxima treats Non-ASCII chars as ordinary letters.
if(((!IsASCII(ch))) || isalpha(ch) || (ch == '_'))
{
char cmd[100];
int cmdidx = 0;
memset(cmd,0,100);
cmd[cmdidx++] = ch;
i++;
for (; i < lengthDoc; i++)
{
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if(ch == '\\')
{
if(cmdidx < 99)
cmd[cmdidx++] = ch;
i++;
if(cmdidx < 99)
cmd[cmdidx++] = ch;
continue;
}
if(isMaximaoperator(ch) || ((IsASCII(ch) && !isalpha(ch) && !isdigit(ch) && (ch != '_'))))
{
i--;
break;
}
if(cmdidx < 99)
cmd[cmdidx++] = ch;
}
// A few known keywords
if(
(strncmp(cmd,"if",99) == 0) ||
(strncmp(cmd,"then",99) == 0) ||
(strncmp(cmd,"else",99) == 0) ||
(strncmp(cmd,"thru",99) == 0) ||
(strncmp(cmd,"for",99) == 0) ||
(strncmp(cmd,"while",99) == 0) ||
(strncmp(cmd,"do",99) == 0)
)
{
styler.ColourTo(i, SCE_MAXIMA_COMMAND);
continue;
}
// All other keywords are functions if they are followed
// by an opening parenthesis
char nextNonwhitespace = ' ';
for (Sci_PositionU o = i + 1; o < lengthDoc; o++)
{
nextNonwhitespace = styler.SafeGetCharAt(o);
if(!IsASCII(nextNonwhitespace) || !isspacechar(nextNonwhitespace))
break;
}
if(nextNonwhitespace == '(')
{
styler.ColourTo(i, SCE_MAXIMA_COMMAND);
}
else
{
styler.ColourTo(i, SCE_MAXIMA_VARIABLE);
}
continue;
}
styler.ColourTo(i-1, SCE_MAXIMA_UNKNOWN);
}
}
LexerModule lmMaxima(SCLEX_MAXIMA, ColouriseMaximaDoc, "maxima", 0, 0);

View File

@ -0,0 +1,404 @@
// Scintilla source code edit control
// @file LexMetapost.cxx - general context conformant metapost coloring scheme
// Author: Hans Hagen - PRAGMA ADE - Hasselt NL - www.pragma-ade.com
// Version: September 28, 2003
// Modified by instanton: July 10, 2007
// Folding based on keywordlists[]
// Copyright: 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
// This lexer is derived from the one written for the texwork environment (1999++) which in
// turn is inspired on texedit (1991++) which finds its roots in wdt (1986).
#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;
// val SCE_METAPOST_DEFAULT = 0
// val SCE_METAPOST_SPECIAL = 1
// val SCE_METAPOST_GROUP = 2
// val SCE_METAPOST_SYMBOL = 3
// val SCE_METAPOST_COMMAND = 4
// val SCE_METAPOST_TEXT = 5
// Definitions in SciTEGlobal.properties:
//
// Metapost Highlighting
//
// # Default
// style.metapost.0=fore:#7F7F00
// # Special
// style.metapost.1=fore:#007F7F
// # Group
// style.metapost.2=fore:#880000
// # Symbol
// style.metapost.3=fore:#7F7F00
// # Command
// style.metapost.4=fore:#008800
// # Text
// style.metapost.5=fore:#000000
// lexer.tex.comment.process=0
// Auxiliary functions:
static inline bool endOfLine(Accessor &styler, Sci_PositionU i) {
return
(styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')) ;
}
static inline bool isMETAPOSTcomment(int ch) {
return
(ch == '%') ;
}
static inline bool isMETAPOSTone(int ch) {
return
(ch == '[') || (ch == ']') || (ch == '(') || (ch == ')') ||
(ch == ':') || (ch == '=') || (ch == '<') || (ch == '>') ||
(ch == '{') || (ch == '}') || (ch == '\'') || (ch == '\"') ;
}
static inline bool isMETAPOSTtwo(int ch) {
return
(ch == ';') || (ch == '$') || (ch == '@') || (ch == '#');
}
static inline bool isMETAPOSTthree(int ch) {
return
(ch == '.') || (ch == '-') || (ch == '+') || (ch == '/') ||
(ch == '*') || (ch == ',') || (ch == '|') || (ch == '`') ||
(ch == '!') || (ch == '?') || (ch == '^') || (ch == '&') ||
(ch == '%') ;
}
static inline bool isMETAPOSTidentifier(int ch) {
return
((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
(ch == '_') ;
}
static inline bool isMETAPOSTnumber(int ch) {
return
(ch >= '0') && (ch <= '9') ;
}
static inline bool isMETAPOSTstring(int ch) {
return
(ch == '\"') ;
}
static inline bool isMETAPOSTcolon(int ch) {
return
(ch == ':') ;
}
static inline bool isMETAPOSTequal(int ch) {
return
(ch == '=') ;
}
static int CheckMETAPOSTInterface(
Sci_PositionU startPos,
Sci_Position length,
Accessor &styler,
int defaultInterface) {
char lineBuffer[1024] ;
Sci_PositionU linePos = 0 ;
// some day we can make something lexer.metapost.mapping=(none,0)(metapost,1)(mp,1)(metafun,2)...
if (styler.SafeGetCharAt(0) == '%') {
for (Sci_PositionU i = 0; i < startPos + length; i++) {
lineBuffer[linePos++] = styler.SafeGetCharAt(i) ;
if (endOfLine(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
lineBuffer[linePos] = '\0';
if (strstr(lineBuffer, "interface=none")) {
return 0 ;
} else if (strstr(lineBuffer, "interface=metapost") || strstr(lineBuffer, "interface=mp")) {
return 1 ;
} else if (strstr(lineBuffer, "interface=metafun")) {
return 2 ;
} else if (styler.SafeGetCharAt(1) == 'D' && strstr(lineBuffer, "%D \\module")) {
// better would be to limit the search to just one line
return 2 ;
} else {
return defaultInterface ;
}
}
}
}
return defaultInterface ;
}
static void ColouriseMETAPOSTDoc(
Sci_PositionU startPos,
Sci_Position length,
int,
WordList *keywordlists[],
Accessor &styler) {
styler.StartAt(startPos) ;
styler.StartSegment(startPos) ;
bool processComment = styler.GetPropertyInt("lexer.metapost.comment.process", 0) == 1 ;
int defaultInterface = styler.GetPropertyInt("lexer.metapost.interface.default", 1) ;
int currentInterface = CheckMETAPOSTInterface(startPos,length,styler,defaultInterface) ;
// 0 no keyword highlighting
// 1 metapost keyword hightlighting
// 2+ metafun keyword hightlighting
int extraInterface = 0 ;
if (currentInterface != 0) {
extraInterface = currentInterface ;
}
WordList &keywords = *keywordlists[0] ;
WordList kwEmpty;
WordList &keywords2 = (extraInterface > 0) ? *keywordlists[extraInterface - 1] : kwEmpty;
StyleContext sc(startPos, length, SCE_METAPOST_TEXT, styler) ;
char key[100] ;
bool inTeX = false ;
bool inComment = false ;
bool inString = false ;
bool inClause = false ;
bool going = sc.More() ; // needed because of a fuzzy end of file state
for (; going; sc.Forward()) {
if (! sc.More()) { going = false ; } // we need to go one behind the end of text
if (inClause) {
sc.SetState(SCE_METAPOST_TEXT) ;
inClause = false ;
}
if (inComment) {
if (sc.atLineEnd) {
sc.SetState(SCE_METAPOST_TEXT) ;
inTeX = false ;
inComment = false ;
inClause = false ;
inString = false ; // not correct but we want to stimulate one-lines
}
} else if (inString) {
if (isMETAPOSTstring(sc.ch)) {
sc.SetState(SCE_METAPOST_SPECIAL) ;
sc.ForwardSetState(SCE_METAPOST_TEXT) ;
inString = false ;
} else if (sc.atLineEnd) {
sc.SetState(SCE_METAPOST_TEXT) ;
inTeX = false ;
inComment = false ;
inClause = false ;
inString = false ; // not correct but we want to stimulate one-lines
}
} else {
if ((! isMETAPOSTidentifier(sc.ch)) && (sc.LengthCurrent() > 0)) {
if (sc.state == SCE_METAPOST_COMMAND) {
sc.GetCurrent(key, sizeof(key)) ;
if ((strcmp(key,"btex") == 0) || (strcmp(key,"verbatimtex") == 0)) {
sc.ChangeState(SCE_METAPOST_GROUP) ;
inTeX = true ;
} else if (inTeX) {
if (strcmp(key,"etex") == 0) {
sc.ChangeState(SCE_METAPOST_GROUP) ;
inTeX = false ;
} else {
sc.ChangeState(SCE_METAPOST_TEXT) ;
}
} else {
if (keywords && keywords.InList(key)) {
sc.ChangeState(SCE_METAPOST_COMMAND) ;
} else if (keywords2 && keywords2.InList(key)) {
sc.ChangeState(SCE_METAPOST_EXTRA) ;
} else {
sc.ChangeState(SCE_METAPOST_TEXT) ;
}
}
}
}
if (isMETAPOSTcomment(sc.ch)) {
if (! inTeX) {
sc.SetState(SCE_METAPOST_SYMBOL) ;
sc.ForwardSetState(SCE_METAPOST_DEFAULT) ;
inComment = ! processComment ;
} else {
sc.SetState(SCE_METAPOST_TEXT) ;
}
} else if (isMETAPOSTstring(sc.ch)) {
if (! inTeX) {
sc.SetState(SCE_METAPOST_SPECIAL) ;
if (! isMETAPOSTstring(sc.chNext)) {
sc.ForwardSetState(SCE_METAPOST_TEXT) ;
}
inString = true ;
} else {
sc.SetState(SCE_METAPOST_TEXT) ;
}
} else if (isMETAPOSTcolon(sc.ch)) {
if (! inTeX) {
if (! isMETAPOSTequal(sc.chNext)) {
sc.SetState(SCE_METAPOST_COMMAND) ;
inClause = true ;
} else {
sc.SetState(SCE_METAPOST_SPECIAL) ;
}
} else {
sc.SetState(SCE_METAPOST_TEXT) ;
}
} else if (isMETAPOSTone(sc.ch)) {
if (! inTeX) {
sc.SetState(SCE_METAPOST_SPECIAL) ;
} else {
sc.SetState(SCE_METAPOST_TEXT) ;
}
} else if (isMETAPOSTtwo(sc.ch)) {
if (! inTeX) {
sc.SetState(SCE_METAPOST_GROUP) ;
} else {
sc.SetState(SCE_METAPOST_TEXT) ;
}
} else if (isMETAPOSTthree(sc.ch)) {
if (! inTeX) {
sc.SetState(SCE_METAPOST_SYMBOL) ;
} else {
sc.SetState(SCE_METAPOST_TEXT) ;
}
} else if (isMETAPOSTidentifier(sc.ch)) {
if (sc.state != SCE_METAPOST_COMMAND) {
sc.SetState(SCE_METAPOST_TEXT) ;
sc.ChangeState(SCE_METAPOST_COMMAND) ;
}
} else if (isMETAPOSTnumber(sc.ch)) {
// rather redundant since for the moment we don't handle numbers
sc.SetState(SCE_METAPOST_TEXT) ;
} else if (sc.atLineEnd) {
sc.SetState(SCE_METAPOST_TEXT) ;
inTeX = false ;
inComment = false ;
inClause = false ;
inString = false ;
} else {
sc.SetState(SCE_METAPOST_TEXT) ;
}
}
}
sc.Complete();
}
// Hooks info the system:
static const char * const metapostWordListDesc[] = {
"MetaPost",
"MetaFun",
0
} ;
static int classifyFoldPointMetapost(const char* s,WordList *keywordlists[]) {
WordList& keywordsStart=*keywordlists[3];
WordList& keywordsStop1=*keywordlists[4];
if (keywordsStart.InList(s)) {return 1;}
else if (keywordsStop1.InList(s)) {return -1;}
return 0;
}
static int ParseMetapostWord(Sci_PositionU pos, Accessor &styler, char *word)
{
int length=0;
char ch=styler.SafeGetCharAt(pos);
*word=0;
while(isMETAPOSTidentifier(ch) && isalpha(ch) && length<100){
word[length]=ch;
length++;
ch=styler.SafeGetCharAt(pos+length);
}
word[length]=0;
return length;
}
static void FoldMetapostDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *keywordlists[], Accessor &styler)
{
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
Sci_PositionU endPos = startPos+length;
int visibleChars=0;
Sci_Position lineCurrent=styler.GetLine(startPos);
int levelPrev=styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent=levelPrev;
char chNext=styler[startPos];
char buffer[100]="";
for (Sci_PositionU i=startPos; i < endPos; i++) {
char ch=chNext;
chNext=styler.SafeGetCharAt(i+1);
char chPrev=styler.SafeGetCharAt(i-1);
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
if(i==0 || chPrev == '\r' || chPrev=='\n'|| chPrev==' '|| chPrev=='(' || chPrev=='$')
{
ParseMetapostWord(i, styler, buffer);
levelCurrent += classifyFoldPointMetapost(buffer,keywordlists);
}
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);
}
LexerModule lmMETAPOST(SCLEX_METAPOST, ColouriseMETAPOSTDoc, "metapost", FoldMetapostDoc, metapostWordListDesc);

View File

@ -0,0 +1,746 @@
// -*- coding: utf-8 -*-
// Scintilla source code edit control
/**
* @file LexModula.cxx
* @author Dariusz "DKnoto" Knociński
* @date 2011/02/03
* @brief Lexer for Modula-2/3 documents.
*/
// 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 "PropSetSimple.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
using namespace Lexilla;
#ifdef DEBUG_LEX_MODULA
#define DEBUG_STATE( p, c )\
fprintf( stderr, "Unknown state: currentPos = %u, char = '%c'\n", static_cast<unsigned int>(p), c );
#else
#define DEBUG_STATE( p, c )
#endif
static inline bool IsDigitOfBase( unsigned ch, unsigned base ) {
if( ch < '0' || ch > 'f' ) return false;
if( base <= 10 ) {
if( ch >= ( '0' + base ) ) return false;
} else {
if( ch > '9' ) {
unsigned nb = base - 10;
if( ( ch < 'A' ) || ( ch >= ( 'A' + nb ) ) ) {
if( ( ch < 'a' ) || ( ch >= ( 'a' + nb ) ) ) {
return false;
}
}
}
}
return true;
}
static inline unsigned IsOperator( StyleContext & sc, WordList & op ) {
int i;
char s[3];
s[0] = sc.ch;
s[1] = sc.chNext;
s[2] = 0;
for( i = 0; i < op.Length(); i++ ) {
if( ( strlen( op.WordAt(i) ) == 2 ) &&
( s[0] == op.WordAt(i)[0] && s[1] == op.WordAt(i)[1] ) ) {
return 2;
}
}
s[1] = 0;
for( i = 0; i < op.Length(); i++ ) {
if( ( strlen( op.WordAt(i) ) == 1 ) &&
( s[0] == op.WordAt(i)[0] ) ) {
return 1;
}
}
return 0;
}
static inline bool IsEOL( Accessor &styler, Sci_PositionU curPos ) {
unsigned ch = styler.SafeGetCharAt( curPos );
if( ( ch == '\r' && styler.SafeGetCharAt( curPos + 1 ) == '\n' ) ||
( ch == '\n' && styler.SafeGetCharAt( curPos - 1 ) != '\r' ) ) {
return true;
}
return false;
}
static inline bool checkStatement(
Accessor &styler,
Sci_Position &curPos,
const char *stt, bool spaceAfter = true ) {
int len = static_cast<int>(strlen( stt ));
int i;
for( i = 0; i < len; i++ ) {
if( styler.SafeGetCharAt( curPos + i ) != stt[i] ) {
return false;
}
}
if( spaceAfter ) {
if( ! isspace( styler.SafeGetCharAt( curPos + i ) ) ) {
return false;
}
}
curPos += ( len - 1 );
return true;
}
static inline bool checkEndSemicolon(
Accessor &styler,
Sci_Position &curPos, Sci_Position endPos )
{
const char *stt = "END";
int len = static_cast<int>(strlen( stt ));
int i;
for( i = 0; i < len; i++ ) {
if( styler.SafeGetCharAt( curPos + i ) != stt[i] ) {
return false;
}
}
while( isspace( styler.SafeGetCharAt( curPos + i ) ) ) {
i++;
if( ( curPos + i ) >= endPos ) return false;
}
if( styler.SafeGetCharAt( curPos + i ) != ';' ) {
return false;
}
curPos += ( i - 1 );
return true;
}
static inline bool checkKeyIdentOper(
Accessor &styler,
Sci_Position &curPos, Sci_Position endPos,
const char *stt, const char etk ) {
Sci_Position newPos = curPos;
if( ! checkStatement( styler, newPos, stt ) )
return false;
newPos++;
if( newPos >= endPos )
return false;
if( ! isspace( styler.SafeGetCharAt( newPos ) ) )
return false;
newPos++;
if( newPos >= endPos )
return false;
while( isspace( styler.SafeGetCharAt( newPos ) ) ) {
newPos++;
if( newPos >= endPos )
return false;
}
if( ! isalpha( styler.SafeGetCharAt( newPos ) ) )
return false;
newPos++;
if( newPos >= endPos )
return false;
char ch;
ch = styler.SafeGetCharAt( newPos );
while( isalpha( ch ) || isdigit( ch ) || ch == '_' ) {
newPos++;
if( newPos >= endPos ) return false;
ch = styler.SafeGetCharAt( newPos );
}
while( isspace( styler.SafeGetCharAt( newPos ) ) ) {
newPos++;
if( newPos >= endPos ) return false;
}
if( styler.SafeGetCharAt( newPos ) != etk )
return false;
curPos = newPos;
return true;
}
static void FoldModulaDoc( Sci_PositionU startPos,
Sci_Position length,
int , WordList *[],
Accessor &styler)
{
Sci_Position curLine = styler.GetLine(startPos);
int curLevel = SC_FOLDLEVELBASE;
Sci_Position endPos = startPos + length;
if( curLine > 0 )
curLevel = styler.LevelAt( curLine - 1 ) >> 16;
Sci_Position curPos = startPos;
int style = styler.StyleAt( curPos );
int visChars = 0;
int nextLevel = curLevel;
while( curPos < endPos ) {
if( ! isspace( styler.SafeGetCharAt( curPos ) ) ) visChars++;
switch( style ) {
case SCE_MODULA_COMMENT:
if( checkStatement( styler, curPos, "(*" ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "*)" ) )
nextLevel--;
break;
case SCE_MODULA_DOXYCOMM:
if( checkStatement( styler, curPos, "(**", false ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "*)" ) )
nextLevel--;
break;
case SCE_MODULA_KEYWORD:
if( checkStatement( styler, curPos, "IF" ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "BEGIN" ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "TRY" ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "LOOP" ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "FOR" ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "WHILE" ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "REPEAT" ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "UNTIL" ) )
nextLevel--;
else
if( checkStatement( styler, curPos, "WITH" ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "CASE" ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "TYPECASE" ) )
nextLevel++;
else
if( checkStatement( styler, curPos, "LOCK" ) )
nextLevel++;
else
if( checkKeyIdentOper( styler, curPos, endPos, "PROCEDURE", '(' ) )
nextLevel++;
else
if( checkKeyIdentOper( styler, curPos, endPos, "END", ';' ) ) {
Sci_Position cln = curLine;
int clv_old = curLevel;
Sci_Position pos;
char ch;
int clv_new;
while( cln > 0 ) {
clv_new = styler.LevelAt( cln - 1 ) >> 16;
if( clv_new < clv_old ) {
nextLevel--;
pos = styler.LineStart( cln );
while( ( ch = styler.SafeGetCharAt( pos, '\n' )) != '\n') {
if( ch == 'P' ) {
if( styler.StyleAt(pos) == SCE_MODULA_KEYWORD ) {
if( checkKeyIdentOper( styler, pos, endPos,
"PROCEDURE", '(' ) ) {
break;
}
}
}
pos++;
}
clv_old = clv_new;
}
cln--;
}
}
else
if( checkKeyIdentOper( styler, curPos, endPos, "END", '.' ) )
nextLevel--;
else
if( checkEndSemicolon( styler, curPos, endPos ) )
nextLevel--;
else {
while( styler.StyleAt( curPos + 1 ) == SCE_MODULA_KEYWORD )
curPos++;
}
break;
default:
break;
}
if( IsEOL( styler, curPos ) || ( curPos == endPos - 1 ) ) {
int efectiveLevel = curLevel | nextLevel << 16;
if( visChars == 0 )
efectiveLevel |= SC_FOLDLEVELWHITEFLAG;
if( curLevel < nextLevel )
efectiveLevel |= SC_FOLDLEVELHEADERFLAG;
if( efectiveLevel != styler.LevelAt(curLine) ) {
styler.SetLevel(curLine, efectiveLevel );
}
curLine++;
curLevel = nextLevel;
if( IsEOL( styler, curPos ) && ( curPos == endPos - 1 ) ) {
styler.SetLevel( curLine, ( curLevel | curLevel << 16)
| SC_FOLDLEVELWHITEFLAG);
}
visChars = 0;
}
curPos++;
style = styler.StyleAt( curPos );
}
}
static inline bool skipWhiteSpaces( StyleContext & sc ) {
while( isspace( sc.ch ) ) {
sc.SetState( SCE_MODULA_DEFAULT );
if( sc.More() )
sc.Forward();
else
return false;
}
return true;
}
static void ColouriseModulaDoc( Sci_PositionU startPos,
Sci_Position length,
int initStyle,
WordList *wl[],
Accessor &styler ) {
WordList& keyWords = *wl[0];
WordList& reservedWords = *wl[1];
WordList& operators = *wl[2];
WordList& pragmaWords = *wl[3];
WordList& escapeCodes = *wl[4];
WordList& doxyKeys = *wl[5];
const int BUFLEN = 128;
char buf[BUFLEN];
int i, kl;
Sci_Position charPos = 0;
StyleContext sc( startPos, length, initStyle, styler );
while( sc.More() ) {
switch( sc.state ) {
case SCE_MODULA_DEFAULT:
if( ! skipWhiteSpaces( sc ) ) break;
if( sc.ch == '(' && sc.chNext == '*' ) {
if( sc.GetRelative(2) == '*' ) {
sc.SetState( SCE_MODULA_DOXYCOMM );
sc.Forward();
} else {
sc.SetState( SCE_MODULA_COMMENT );
}
sc.Forward();
}
else
if( isalpha( sc.ch ) ) {
if( isupper( sc.ch ) && isupper( sc.chNext ) ) {
for( i = 0; i < BUFLEN - 1; i++ ) {
buf[i] = sc.GetRelative(i);
if( !isalpha( buf[i] ) && !(buf[i] == '_') )
break;
}
kl = i;
buf[kl] = 0;
if( keyWords.InList( buf ) ) {
sc.SetState( SCE_MODULA_KEYWORD );
sc.Forward( kl );
sc.SetState( SCE_MODULA_DEFAULT );
continue;
}
else
if( reservedWords.InList( buf ) ) {
sc.SetState( SCE_MODULA_RESERVED );
sc.Forward( kl );
sc.SetState( SCE_MODULA_DEFAULT );
continue;
} else {
/** check procedure identifier */
sc.Forward( kl );
continue;
}
} else {
for( i = 0; i < BUFLEN - 1; i++ ) {
buf[i] = sc.GetRelative(i);
if( !isalpha( buf[i] ) &&
!isdigit( buf[i] ) &&
!(buf[i] == '_') )
break;
}
kl = i;
buf[kl] = 0;
sc.SetState( SCE_MODULA_DEFAULT );
sc.Forward( kl );
continue;
}
}
else
if( isdigit( sc.ch ) ) {
sc.SetState( SCE_MODULA_NUMBER );
continue;
}
else
if( sc.ch == '\"' ) {
sc.SetState( SCE_MODULA_STRING );
}
else
if( sc.ch == '\'' ) {
charPos = sc.currentPos;
sc.SetState( SCE_MODULA_CHAR );
}
else
if( sc.ch == '<' && sc.chNext == '*' ) {
sc.SetState( SCE_MODULA_PRAGMA );
sc.Forward();
} else {
unsigned len = IsOperator( sc, operators );
if( len > 0 ) {
sc.SetState( SCE_MODULA_OPERATOR );
sc.Forward( len );
sc.SetState( SCE_MODULA_DEFAULT );
continue;
} else {
DEBUG_STATE( sc.currentPos, sc.ch );
}
}
break;
case SCE_MODULA_COMMENT:
if( sc.ch == '*' && sc.chNext == ')' ) {
sc.Forward( 2 );
sc.SetState( SCE_MODULA_DEFAULT );
continue;
}
break;
case SCE_MODULA_DOXYCOMM:
switch( sc.ch ) {
case '*':
if( sc.chNext == ')' ) {
sc.Forward( 2 );
sc.SetState( SCE_MODULA_DEFAULT );
continue;
}
break;
case '@':
if( islower( sc.chNext ) ) {
for( i = 0; i < BUFLEN - 1; i++ ) {
buf[i] = sc.GetRelative(i+1);
if( isspace( buf[i] ) ) break;
}
buf[i] = 0;
kl = i;
if( doxyKeys.InList( buf ) ) {
sc.SetState( SCE_MODULA_DOXYKEY );
sc.Forward( kl + 1 );
sc.SetState( SCE_MODULA_DOXYCOMM );
}
}
break;
default:
break;
}
break;
case SCE_MODULA_NUMBER:
{
buf[0] = sc.ch;
for( i = 1; i < BUFLEN - 1; i++ ) {
buf[i] = sc.GetRelative(i);
if( ! isdigit( buf[i] ) )
break;
}
kl = i;
buf[kl] = 0;
switch( sc.GetRelative(kl) ) {
case '_':
{
int base = atoi( buf );
if( base < 2 || base > 16 ) {
sc.SetState( SCE_MODULA_BADSTR );
} else {
int imax;
kl++;
for( i = 0; i < BUFLEN - 1; i++ ) {
buf[i] = sc.GetRelative(kl+i);
if( ! IsDigitOfBase( buf[i], 16 ) ) {
break;
}
}
imax = i;
for( i = 0; i < imax; i++ ) {
if( ! IsDigitOfBase( buf[i], base ) ) {
sc.SetState( SCE_MODULA_BADSTR );
break;
}
}
kl += imax;
}
sc.SetState( SCE_MODULA_BASENUM );
for( i = 0; i < kl; i++ ) {
sc.Forward();
}
sc.SetState( SCE_MODULA_DEFAULT );
continue;
}
break;
case '.':
if( sc.GetRelative(kl+1) == '.' ) {
kl--;
for( i = 0; i < kl; i++ ) {
sc.Forward();
}
sc.Forward();
sc.SetState( SCE_MODULA_DEFAULT );
continue;
} else {
bool doNext = false;
kl++;
buf[0] = sc.GetRelative(kl);
if( isdigit( buf[0] ) ) {
for( i = 0;; i++ ) {
if( !isdigit(sc.GetRelative(kl+i)) )
break;
}
kl += i;
buf[0] = sc.GetRelative(kl);
switch( buf[0] )
{
case 'E':
case 'e':
case 'D':
case 'd':
case 'X':
case 'x':
kl++;
buf[0] = sc.GetRelative(kl);
if( buf[0] == '-' || buf[0] == '+' ) {
kl++;
}
buf[0] = sc.GetRelative(kl);
if( isdigit( buf[0] ) ) {
for( i = 0;; i++ ) {
if( !isdigit(sc.GetRelative(kl+i)) ) {
buf[0] = sc.GetRelative(kl+i);
break;
}
}
kl += i;
doNext = true;
} else {
sc.SetState( SCE_MODULA_BADSTR );
}
break;
default:
doNext = true;
break;
}
} else {
sc.SetState( SCE_MODULA_BADSTR );
}
if( doNext ) {
if( ! isspace( buf[0] ) &&
buf[0] != ')' &&
buf[0] != '>' &&
buf[0] != '<' &&
buf[0] != '=' &&
buf[0] != '#' &&
buf[0] != '+' &&
buf[0] != '-' &&
buf[0] != '*' &&
buf[0] != '/' &&
buf[0] != ',' &&
buf[0] != ';'
) {
sc.SetState( SCE_MODULA_BADSTR );
} else {
kl--;
}
}
}
sc.SetState( SCE_MODULA_FLOAT );
for( i = 0; i < kl; i++ ) {
sc.Forward();
}
sc.SetState( SCE_MODULA_DEFAULT );
continue;
break;
default:
for( i = 0; i < kl; i++ ) {
sc.Forward();
}
break;
}
sc.SetState( SCE_MODULA_DEFAULT );
continue;
}
break;
case SCE_MODULA_STRING:
if( sc.ch == '\"' ) {
sc.Forward();
sc.SetState( SCE_MODULA_DEFAULT );
continue;
} else {
if( sc.ch == '\\' ) {
i = 1;
if( IsDigitOfBase( sc.chNext, 8 ) ) {
for( i = 1; i < BUFLEN - 1; i++ ) {
if( ! IsDigitOfBase(sc.GetRelative(i+1), 8 ) )
break;
}
if( i == 3 ) {
sc.SetState( SCE_MODULA_STRSPEC );
} else {
sc.SetState( SCE_MODULA_BADSTR );
}
} else {
buf[0] = sc.chNext;
buf[1] = 0;
if( escapeCodes.InList( buf ) ) {
sc.SetState( SCE_MODULA_STRSPEC );
} else {
sc.SetState( SCE_MODULA_BADSTR );
}
}
sc.Forward(i+1);
sc.SetState( SCE_MODULA_STRING );
continue;
}
}
break;
case SCE_MODULA_CHAR:
if( sc.ch == '\'' ) {
sc.Forward();
sc.SetState( SCE_MODULA_DEFAULT );
continue;
}
else
if( ( sc.currentPos - charPos ) == 1 ) {
if( sc.ch == '\\' ) {
i = 1;
if( IsDigitOfBase( sc.chNext, 8 ) ) {
for( i = 1; i < BUFLEN - 1; i++ ) {
if( ! IsDigitOfBase(sc.GetRelative(i+1), 8 ) )
break;
}
if( i == 3 ) {
sc.SetState( SCE_MODULA_CHARSPEC );
} else {
sc.SetState( SCE_MODULA_BADSTR );
}
} else {
buf[0] = sc.chNext;
buf[1] = 0;
if( escapeCodes.InList( buf ) ) {
sc.SetState( SCE_MODULA_CHARSPEC );
} else {
sc.SetState( SCE_MODULA_BADSTR );
}
}
sc.Forward(i+1);
sc.SetState( SCE_MODULA_CHAR );
continue;
}
} else {
sc.SetState( SCE_MODULA_BADSTR );
sc.Forward();
sc.SetState( SCE_MODULA_CHAR );
continue;
}
break;
case SCE_MODULA_PRAGMA:
if( sc.ch == '*' && sc.chNext == '>' ) {
sc.Forward();
sc.Forward();
sc.SetState( SCE_MODULA_DEFAULT );
continue;
}
else
if( isupper( sc.ch ) && isupper( sc.chNext ) ) {
buf[0] = sc.ch;
buf[1] = sc.chNext;
for( i = 2; i < BUFLEN - 1; i++ ) {
buf[i] = sc.GetRelative(i);
if( !isupper( buf[i] ) )
break;
}
kl = i;
buf[kl] = 0;
if( pragmaWords.InList( buf ) ) {
sc.SetState( SCE_MODULA_PRGKEY );
sc.Forward( kl );
sc.SetState( SCE_MODULA_PRAGMA );
continue;
}
}
break;
default:
break;
}
sc.Forward();
}
sc.Complete();
}
static const char *const modulaWordListDesc[] =
{
"Keywords",
"ReservedKeywords",
"Operators",
"PragmaKeyswords",
"EscapeCodes",
"DoxygeneKeywords",
0
};
LexerModule lmModula( SCLEX_MODULA, ColouriseModulaDoc, "modula", FoldModulaDoc,
modulaWordListDesc);

Some files were not shown because too many files have changed in this diff Show More