Merge pull request #5683 from RaiKoHoff/Dev_Master

upd: Lexilla Lib v5.4.8 and Scintilla v5.6.1
This commit is contained in:
Rainer Kottenhoff 2026-04-16 01:47:12 +02:00 committed by GitHub
commit 09a71483fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 2780 additions and 724 deletions

View File

@ -102,7 +102,6 @@ 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
@ -113,7 +112,6 @@ constParameterReference:lexilla/lexers/LexLaTeX.cxx
constParameterReference:lexilla/lexers/LexLisp.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
@ -240,7 +238,6 @@ constVariableReference:lexilla/lexers/LexMSSQL.cxx
constVariableReference:lexilla/lexers/LexNsis.cxx
constVariableReference:lexilla/lexers/LexOpal.cxx
constVariableReference:lexilla/lexers/LexPOV.cxx
constVariableReference:lexilla/lexers/LexPascal.cxx
constVariableReference:lexilla/lexers/LexPB.cxx
constVariableReference:lexilla/lexers/LexPowerPro.cxx
constVariableReference:lexilla/lexers/LexPS.cxx

View File

@ -9,7 +9,7 @@
<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="20260225" />
<meta name="Date.Modified" content="20260326" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
.logo {
@ -62,8 +62,8 @@
<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.4.7<br />
Site last modified February 25 2026</font>
<font color="#FFCC99" size="3">Release version 5.4.8<br />
Site last modified March 26 2026</font>
</td>
<td width="20%">
&nbsp;
@ -78,11 +78,11 @@
</tr>
</table>
<ul id="versionlist">
<li>Version 5.4.8 improves Batch, Forth, JavaScript, and JSON.</li>
<li>Version 5.4.7 adds EscapeSequence lexer escseq. Improves Errorlist, Makefile, Perl, and Progress.</li>
<li>Version 5.4.6 adds SINEX lexer. Improves Errorlist, Progress, and Python.</li>
<li>Version 5.4.5 improves Dart, Makefile, Nix, TOML, and Zig.</li>
<li>Version 5.4.4 fixes a problem when building for ARM64 on Windows.</li>
<li>Version 5.4.3 improves C++, Modula 3, Pascal, Python, and Ruby.</li>
</ul>
<ul id="menu">
<li id="remote1"><a href="https://www.scintilla.org/SciTEImage.html">Screenshot</a></li>

View File

@ -26,9 +26,9 @@
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
<tr>
<td>
<font size="4"> <a href="https://www.scintilla.org/lexilla547.zip">
<font size="4"> <a href="https://www.scintilla.org/lexilla548.zip">
Windows</a>&nbsp;&nbsp;
<a href="https://www.scintilla.org/lexilla547.tgz">
<a href="https://www.scintilla.org/lexilla548.tgz">
GTK/Linux</a>&nbsp;&nbsp;
</font>
</td>
@ -42,7 +42,7 @@
containing very few restrictions.
</p>
<h3>
Release 5.4.7
Release 5.4.8
</h3>
<h4>
Source Code
@ -50,8 +50,8 @@
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/lexilla547.zip">zip format</a> (1.4M) commonly used on Windows</li>
<li><a href="https://www.scintilla.org/lexilla547.tgz">tgz format</a> (1.0M) commonly used on Linux and compatible operating systems</li>
<li><a href="https://www.scintilla.org/lexilla548.zip">zip format</a> (1.4M) commonly used on Windows</li>
<li><a href="https://www.scintilla.org/lexilla548.tgz">tgz format</a> (1.0M) 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>

View File

@ -597,6 +597,38 @@
</tr>
</table>
<h2 id="Releases">Releases</h2>
<h3>
<a href="https://www.scintilla.org/lexilla548.zip">Release 5.4.8</a>
</h3>
<ul>
<li>
Released 26 March 2026.
</li>
<li>
Batch: Remove line length limitation and change to an object lexer.
<a href="https://github.com/ScintillaOrg/lexilla/issues/228">Issue #228</a>.
</li>
<li>
Forth: Treat \r\n line ends the same as \n. This makes testing easier.
<a href="https://github.com/ScintillaOrg/lexilla/issues/349">Issue #349</a>.
</li>
<li>
Forth: Allow more Forth words to be symbols or begin with a symbol.
Require whitespace around line comment tokens,
similar to the left-hand parenthesis of stream comments.
<a href="https://github.com/ScintillaOrg/lexilla/issues/351">Issue #351</a>.
</li>
<li>
JavaScript: in cpp lexer, add lexer.cpp.enable.preprocessor and lexer.cpp.allow.hashes properties.
This allows disabling preprocessor recognition (as JavaScript doesn't have a preprocessor) and
recognizing private elements that start with a #.
<a href="https://github.com/ScintillaOrg/lexilla/issues/48">Issue #48</a>.
</li>
<li>
JSON: Fix escaped quote in SCE_JSON_URI.
<a href="https://github.com/ScintillaOrg/lexilla/issues/72">Issue #72</a>.
</li>
</ul>
<h3>
<a href="https://www.scintilla.org/lexilla547.zip">Release 5.4.7</a>
</h3>

View File

@ -492,6 +492,7 @@ public:
bashStruct.Set("if elif fi while until else then do done esac eval");
bashStruct_in.Set("for case select");
testOperator.Set("eq ge gt le lt ne ef nt ot");
SetOptionSet(&osBash);
}
void SCI_METHOD Release() override {
delete this;
@ -499,30 +500,11 @@ public:
int SCI_METHOD Version() const override {
return lvRelease5;
}
const char * SCI_METHOD PropertyNames() override {
return osBash.PropertyNames();
}
int SCI_METHOD PropertyType(const char* name) override {
return osBash.PropertyType(name);
}
const char * SCI_METHOD DescribeProperty(const char *name) override {
return osBash.DescribeProperty(name);
}
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
const char * SCI_METHOD PropertyGet(const char* key) override {
return osBash.PropertyGet(key);
}
const char * SCI_METHOD DescribeWordListSets() override {
return osBash.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 AllocateSubStyles(int styleBase, int numberStyles) override {
return subStyles.Allocate(styleBase, numberStyles);
}

View File

@ -14,6 +14,7 @@
#include <string>
#include <string_view>
#include <map>
#include <initializer_list>
#include "ILexer.h"
@ -27,39 +28,113 @@
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "DefaultLexer.h"
using namespace Lexilla;
namespace {
const char *const batchWordListDesc[] = {
"Internal Commands",
"External Commands",
nullptr
};
const LexicalClass lexicalClasses[] = {
// Lexer batch SCLEX_BATCH SCE_BAT_
0, "SCE_BAT_DEFAULT", "default", "White space",
1, "SCE_BAT_COMMENT", "comment", "Line comment",
2, "SCE_BAT_WORD", "keyword", "Keyword",
3, "SCE_BAT_LABEL", "label", "Label",
4, "SCE_BAT_HIDE", "preprocessor", "Hide line @",
5, "SCE_BAT_COMMAND", "identifier", "Command",
6, "SCE_BAT_IDENTIFIER", "identifier", "Identifier",
7, "SCE_BAT_OPERATOR", "operator", "Operator",
8, "SCE_BAT_AFTER_LABEL", "comment","After label",
};
class LexerBatch : public DefaultLexer {
WordList keywords;
WordList keywords2;
std::string wordLists;
public:
explicit LexerBatch() :
DefaultLexer("batch", SCLEX_BATCH, lexicalClasses, std::size(lexicalClasses)) {
wordLists = JoinWordListDescriptions(batchWordListDesc);
}
LexerBatch(const LexerBatch &) = delete;
LexerBatch(LexerBatch &&) = delete;
LexerBatch &operator=(const LexerBatch &) = delete;
LexerBatch &operator=(LexerBatch &&) = delete;
~LexerBatch() override = default;
const char *SCI_METHOD DescribeWordListSets() override {
return wordLists.c_str();
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, Scintilla::IDocument *pAccess) override;
static ILexer5 *LexerFactoryBatch() {
return new LexerBatch();
}
};
constexpr bool Is0To9(char ch) noexcept {
return (ch >= '0') && (ch <= '9');
}
bool IsAlphabetic(int ch) noexcept {
return IsASCII(ch) && isalpha(ch);
constexpr bool IsAlphabetic(int ch) noexcept {
return IsUpperOrLowerCase(ch);
}
inline bool AtEOL(Accessor &styler, Sci_PositionU i) {
bool AtEOL(LexAccessor &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 == ')');
return AnyOf(ch, '=', '+', '>', '<', '|', '?', '*', '&', '(', ')');
}
// Tests for BATCH Separators
constexpr bool IsBSeparator(char ch) noexcept {
return (ch == '\\') || (ch == '.') || (ch == ';') ||
(ch == '\"') || (ch == '\'') || (ch == '/');
return AnyOf(ch, '\\', '.', ';', '\"', '\'', '/');
}
// Both operators and separators -- words often ended with these characters.
constexpr bool IsBPunctuation(char ch) noexcept {
return IsBOperator(ch) || IsBSeparator(ch);
}
// These characters end words.
constexpr bool IsBEndWord(char ch) noexcept {
return IsBPunctuation(ch) || AnyOf(ch, '%', '!');
}
constexpr void SkipSpace(Sci_PositionU &i, std::string_view sv) noexcept {
while (i < sv.length() && isspacechar(sv[i])) {
i++;
}
}
constexpr void SkipNonSpace(Sci_PositionU &i, std::string_view sv) noexcept {
while (i < sv.length() && !isspacechar(sv[i])) {
i++;
}
}
constexpr Sci_PositionU WordLength(std::string_view word) {
Sci_PositionU i = 0;
while ((i < word.length()) && (!IsBEndWord(word[i]))) {
i++;
}
return i;
}
// Tests for escape character
constexpr bool IsEscaped(const char* wordStr, Sci_PositionU pos) noexcept {
constexpr bool IsEscaped(std::string_view wordStr, Sci_PositionU pos) noexcept {
bool isQoted=false;
while (pos>0){
pos--;
@ -75,7 +150,7 @@ 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)) {
if (!IsEscaped(svBuffer, pQuote)) {
CurrentStatus = !CurrentStatus;
}
pQuote = svBuffer.find(quote, pQuote + 1);
@ -84,17 +159,49 @@ constexpr bool IsQuotedBy(std::string_view svBuffer, char quote) noexcept {
}
// Tests for quote character
constexpr bool textQuoted(const char *lineBuffer, Sci_PositionU endPos) noexcept {
const std::string_view svBuffer(lineBuffer, endPos);
constexpr bool textQuoted(std::string_view lineBuffer, Sci_PositionU endPos) noexcept {
const std::string_view svBuffer = lineBuffer.substr(0, endPos);
return IsQuotedBy(svBuffer, '\"') || IsQuotedBy(svBuffer, '\'');
}
void ColouriseBatchDoc(
Sci_PositionU startPos,
Sci_Position length,
int /*initStyle*/,
WordList *keywordlists[],
Accessor &styler) {
bool IsContinuation(const std::string &lineBuffer) noexcept {
if ((lineBuffer.length() <= 1) || (lineBuffer == "\r\n")) // empty line on Unix and Mac or on Windows
return false;
Sci_PositionU lineContinuationPos = lineBuffer.length() - 2; // Unix or Mac EOL
if ((lineBuffer.length() > 2) && lineBuffer[lineBuffer.length() - 2] == '\r') // Windows EOL
lineContinuationPos = lineBuffer.length() - 3;
// Reset continueProcessing if line continuation was not found
if ((lineBuffer[lineContinuationPos] != '^')
|| IsEscaped(lineBuffer, lineContinuationPos)
|| textQuoted(lineBuffer, lineContinuationPos))
return false;
return true;
}
Sci_Position SCI_METHOD LexerBatch::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) {
if (wordListN->Set(wl)) {
firstModification = 0;
}
}
return firstModification;
}
void LexerBatch::Lex(Sci_PositionU startPos, Sci_Position length, int, Scintilla::IDocument *pAccess) {
LexAccessor styler(pAccess);
// Always backtracks to the start of a line that is not a continuation
// of the previous line
if (startPos > 0) {
@ -113,24 +220,22 @@ void ColouriseBatchDoc(
}
}
char lineBuffer[1024] {};
std::string lineBuffer;
std::string word;
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)) {
// All testing is performed on a lower case version of the line since batch is case-insensitive
lineBuffer.push_back(MakeLowerCase(styler[i]));
if (AtEOL(styler, i) || (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 lengthLine = lineBuffer.length();
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
@ -140,9 +245,7 @@ void ColouriseBatchDoc(
Sci_PositionU offset = 0; // Line Buffer Offset
// Skip initial spaces
while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {
offset++;
}
SkipSpace(offset, lineBuffer);
// Colorize Default Text
styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);
// Set External Command / Program Location
@ -156,13 +259,13 @@ void ColouriseBatchDoc(
} else {
// Colorize Real Label
// :[\t ]*[^\t &+:<>|]+
const char *startLabelName = lineBuffer + offset + 1;
const size_t whitespaceLength = strspn(startLabelName, "\t ");
const size_t whitespaceEnd = lineBuffer.find_first_not_of("\t ", offset + 1);
const size_t whitespaceLength = (whitespaceEnd == std::string::npos) ? 0 : whitespaceEnd;
// 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
const size_t labelEnd = lineBuffer.find_first_of("\t &+:<>|", whitespaceLength);
if (labelEnd != std::string::npos) {
styler.ColourTo(startLine + labelEnd - 1, SCE_BAT_LABEL);
styler.ColourTo(endPos, SCE_BAT_AFTER_LABEL);
} else {
styler.ColourTo(endPos, SCE_BAT_LABEL);
}
@ -185,9 +288,7 @@ void ColouriseBatchDoc(
offset++;
}
// Skip next spaces
while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {
offset++;
}
SkipSpace(offset, lineBuffer);
// Read remainder of line word-at-a-time or remainder-of-word-at-a-time
while (offset < lengthLine && !stopLineProcessing) {
@ -195,95 +296,75 @@ void ColouriseBatchDoc(
// 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);
// Copy word from Line Buffer
const Sci_PositionU wordStart = offset;
SkipNonSpace(offset, lineBuffer);
const Sci_PositionU wbl = offset - wordStart; // Word Buffer Length
// Using assign to prevent new allocations
word.assign(lineBuffer, wordStart, wbl);
const char first = word.front();
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);
if ((word == "rem") || (word.substr(0,2) == "::")) {
if ((offset == wbl) || !textQuoted(lineBuffer, wordStart)) {
styler.ColourTo(startLine + wordStart - 1, SCE_BAT_DEFAULT);
styler.ColourTo(endPos, SCE_BAT_COMMENT);
break;
}
}
}
// Check for Separator
if (IsBSeparator(wordBuffer[0])) {
if (IsBSeparator(first)) {
// Check for External Command / Program
if ((cmdLoc == offset - wbl) &&
((wordBuffer[0] == ':') ||
(wordBuffer[0] == '\\') ||
(wordBuffer[0] == '.'))) {
int style = SCE_BAT_DEFAULT;
if ((cmdLoc == wordStart) &&
(AnyOf(first, ':', '\\', '.'))) {
// Reset Offset to re-process remainder of word
offset -= (wbl - 1);
offset = wordStart + 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);
if ((!keywords2) || (keywords2.InList(word))) {
style = SCE_BAT_COMMAND;
}
// 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);
offset = wordStart + 1;
}
// Colorize Text
styler.ColourTo(startLine + offset - 1, style);
// Check for Regular Keyword in list
} else if ((keywords.InList(wordBuffer)) &&
(continueProcessing)) {
} else if ((keywords.InList(word)) && (continueProcessing)) {
// ECHO, GOTO, PROMPT and SET require no further Regular Keyword Checking
if (InList(wordView, {"echo", "goto", "prompt"})) {
if (InList(word, {"echo", "goto", "prompt"})) {
continueProcessing = false;
}
// SET requires additional processing for the assignment operator
if (wordView == "set") {
if (word == "set") {
continueProcessing = false;
isNotAssigned=true;
}
// Identify External Command / Program Location for ERRORLEVEL, and EXIST
if (InList(wordView, {"errorlevel", "exist"})) {
if (InList(word, {"errorlevel", "exist"})) {
// Reset External Command / Program Location
cmdLoc = offset;
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
SkipSpace(cmdLoc, lineBuffer);
// Skip comparison
while ((cmdLoc < lengthLine) &&
(!isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
SkipNonSpace(cmdLoc, lineBuffer);
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
SkipSpace(cmdLoc, lineBuffer);
// Identify External Command / Program Location for CALL, DO, LOADHIGH and LH
} else if (InList(wordView, {"call", "do", "loadhigh", "lh"})) {
} else if (InList(word, {"call", "do", "loadhigh", "lh"})) {
// Reset External Command / Program Location
cmdLoc = offset;
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
SkipSpace(cmdLoc, lineBuffer);
// Check if call is followed by a label
if ((lineBuffer[cmdLoc] == ':') &&
(wordView == "call")) {
(word == "call")) {
continueProcessing = false;
}
}
@ -291,9 +372,8 @@ void ColouriseBatchDoc(
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])) &&
} else if (
(!(IsBOperator(first) || AnyOf(first, '%', '!'))) &&
(continueProcessing)) {
// Check for Special Keyword
// Affected Commands are in Length range 2-6
@ -302,345 +382,257 @@ void ColouriseBatchDoc(
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';
// Special Keyword used to determine if the first n characters is a Keyword
wbo = keywordLength;
const std::string sKeyword = word.substr(0, keywordLength);
// Check for Special Keyword in list
if ((keywords.InList(sKeywordBuffer)) &&
((IsBOperator(wordBuffer[wbo])) ||
(IsBSeparator(wordBuffer[wbo])) ||
(wordBuffer[wbo] == ':' &&
(InList(sKeywordBuffer, {"call", "echo", "goto"}) )))) {
if ((keywords.InList(sKeyword)) &&
((IsBPunctuation(word[wbo])) ||
(word[wbo] == ':' && (InList(sKeyword, {"call", "echo", "goto"}) )))) {
sKeywordFound = true;
// ECHO requires no further Regular Keyword Checking
if (std::string_view(sKeywordBuffer) == "echo") {
if (sKeyword== "echo") {
continueProcessing = false;
}
// Colorize Special Keyword as Regular Keyword
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_WORD);
styler.ColourTo(startLine + wordStart + wbo - 1, SCE_BAT_WORD);
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
offset = wordStart + wbo;
}
}
// Check for External Command / Program or Default Text
if (!sKeywordFound) {
wbo = 0;
int style = SCE_BAT_DEFAULT;
// Read up to %, !, Operator or Separator
const Sci_PositionU lengthWord = WordLength(word);
// 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++;
}
if (cmdLoc == wordStart) {
// Reset External Command / Program Location
cmdLoc = offset - (wbl - wbo);
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
cmdLoc = wordStart + lengthWord;
// CHOICE requires no further Regular Keyword Checking
if (wordView == "choice") {
if (word == "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;
if (word == "start") {
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
SkipSpace(cmdLoc, lineBuffer);
// Reset External Command / Program Location if command switch detected
if (lineBuffer[cmdLoc] == '/') {
// Skip command switch
while ((cmdLoc < lengthLine) &&
(!isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
SkipNonSpace(cmdLoc, lineBuffer);
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
SkipSpace(cmdLoc, lineBuffer);
}
}
// 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);
if ((!keywords2) || (keywords2.InList(word))) {
style = SCE_BAT_COMMAND;
}
// 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);
}
styler.ColourTo(startLine + wordStart + lengthWord - 1, style);
// Reset Offset to re-process remainder of word
offset = wordStart + lengthWord;
}
// Check for Argument (%n), Environment Variable (%x...%) or Local Variable (%%a)
} else if (wordBuffer[0] == '%') {
} else if (first == '%') {
// Colorize Default Text
styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT);
styler.ColourTo(startLine + wordStart - 1, SCE_BAT_DEFAULT);
wbo++;
// Search to end of word for second % (can be a long path)
while ((wbo < wbl) &&
(wordBuffer[wbo] != '%')) {
while ((wbo < wbl) && (word[wbo] != '%')) {
wbo++;
}
// Check for Argument (%n) or (%*)
if (((Is0To9(wordBuffer[1])) || (wordBuffer[1] == '*')) &&
(wordBuffer[wbo] != '%')) {
if (((Is0To9(word[1])) || (word[1] == '*')) &&
(word[wbo] != '%')) {
// Check for External Command / Program
if (cmdLoc == offset - wbl) {
cmdLoc = offset - (wbl - 2);
if (cmdLoc == wordStart) {
cmdLoc = wordStart + 2;
}
// Colorize Argument
styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_IDENTIFIER);
styler.ColourTo(startLine + wordStart + 1, SCE_BAT_IDENTIFIER);
// Reset Offset to re-process remainder of word
offset -= (wbl - 2);
offset = wordStart + 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] == '~'))) {
} else if (((wbl > 1) && (word[1] == '~')) ||
((wbl > 2) && (word[1] == '%') && (word[2] == '~'))) {
// Check for External Command / Program
if (cmdLoc == offset - wbl) {
cmdLoc = offset - (wbl - wbo);
if (cmdLoc == wordStart) {
cmdLoc = wordStart + wbo;
}
const bool isArgument = (wordBuffer[1] == '~');
const bool isArgument = (word[1] == '~');
if (isArgument) {
Sci_PositionU expansionStopOffset = 2;
bool isValid = false;
for (; expansionStopOffset < wbl; expansionStopOffset++) {
if (Is0To9(wordBuffer[expansionStopOffset])) {
if (Is0To9(word[expansionStopOffset])) {
expansionStopOffset++;
isValid = true;
wbo = expansionStopOffset;
// Colorize Expanded Argument
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);
styler.ColourTo(startLine + wordStart + wbo - 1, SCE_BAT_IDENTIFIER);
break;
}
}
if (!isValid) {
// not a valid expanded argument or variable
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT);
styler.ColourTo(startLine + wordStart + wbo - 1, 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]))) {
while ((wbo < wbl) && (!(IsBPunctuation(word[wbo]) || (word[wbo] == '%')))) {
wbo++;
}
if (wbo > 3) {
// Colorize Expanded Variable
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);
styler.ColourTo(startLine + wordStart + wbo - 1, SCE_BAT_IDENTIFIER);
} else {
// not a valid expanded argument or variable
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT);
styler.ColourTo(startLine + wordStart + wbo - 1, SCE_BAT_DEFAULT);
}
}
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
offset = wordStart + wbo;
// Check for Environment Variable (%x...%)
} else if ((wordBuffer[1] != '%') &&
(wordBuffer[wbo] == '%')) {
} else if ((word[1] != '%') && (word[wbo] == '%')) {
wbo++;
// Check for External Command / Program
if (cmdLoc == offset - wbl) {
cmdLoc = offset - (wbl - wbo);
if (cmdLoc == wordStart) {
cmdLoc = wordStart + wbo;
}
// Colorize Environment Variable
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);
styler.ColourTo(startLine + wordStart + wbo - 1, SCE_BAT_IDENTIFIER);
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
offset = wordStart + wbo;
// Check for Local Variable (%%a)
} else if (
(wbl > 2) &&
(wordBuffer[1] == '%') &&
(wordBuffer[2] != '%') &&
(!IsBOperator(wordBuffer[2])) &&
(!IsBSeparator(wordBuffer[2]))) {
(word[1] == '%') &&
(word[2] != '%') &&
(!IsBPunctuation(word[2]))) {
// Check for External Command / Program
if (cmdLoc == offset - wbl) {
cmdLoc = offset - (wbl - 3);
if (cmdLoc == wordStart) {
cmdLoc = wordStart + 3;
}
// Colorize Local Variable
styler.ColourTo(startLine + offset - 1 - (wbl - 3), SCE_BAT_IDENTIFIER);
styler.ColourTo(startLine + wordStart + 2, SCE_BAT_IDENTIFIER);
// Reset Offset to re-process remainder of word
offset -= (wbl - 3);
offset = wordStart + 3;
// escaped %
} else if (
(wbl > 1) &&
(wordBuffer[1] == '%')) {
(word[1] == '%')) {
// Reset Offset to re-process remainder of word
styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_DEFAULT);
offset -= (wbl - 2);
styler.ColourTo(startLine + wordStart + 1, SCE_BAT_DEFAULT);
offset = wordStart + 2;
}
// Check for Environment Variable (!x...!)
} else if (wordBuffer[0] == '!') {
} else if (first == '!') {
// 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++;
styler.ColourTo(startLine + wordStart - 1, SCE_BAT_DEFAULT);
const size_t nextExclamation = word.find('!', 1);
if (nextExclamation != std::string::npos) {
// Check for External Command / Program
if (cmdLoc == offset - wbl) {
cmdLoc = offset - (wbl - wbo);
if (cmdLoc == wordStart) {
cmdLoc = wordStart + nextExclamation + 1;
}
// Colorize Environment Variable
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);
styler.ColourTo(startLine + wordStart + nextExclamation, SCE_BAT_IDENTIFIER);
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
offset = wordStart + nextExclamation + 1;
}
// Check for Operator
} else if (IsBOperator(wordBuffer[0])) {
} else if (IsBOperator(first)) {
// Colorize Default Text
styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT);
styler.ColourTo(startLine + wordStart - 1, SCE_BAT_DEFAULT);
// Check for Comparison Operator
if ((wordBuffer[0] == '=') && (wordBuffer[1] == '=')) {
if ((first == '=') && (word[1] == '=')) {
// Identify External Command / Program Location for IF
cmdLoc = offset;
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
SkipSpace(cmdLoc, lineBuffer);
// Colorize Comparison Operator
if (continueProcessing)
styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_OPERATOR);
styler.ColourTo(startLine + wordStart + 1, SCE_BAT_OPERATOR);
else
styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_DEFAULT);
styler.ColourTo(startLine + wordStart + 1, SCE_BAT_DEFAULT);
// Reset Offset to re-process remainder of word
offset -= (wbl - 2);
offset = wordStart + 2;
// Check for Pipe Operator
} else if ((wordBuffer[0] == '|') &&
!(IsEscaped(lineBuffer,offset - wbl + wbo) || textQuoted(lineBuffer, offset - wbl) )) {
} else if ((first == '|') &&
!(IsEscaped(lineBuffer, wordStart + wbo) || textQuoted(lineBuffer, wordStart))) {
// Reset External Command / Program Location
cmdLoc = offset - wbl + 1;
cmdLoc = wordStart + 1;
// Skip next spaces
while ((cmdLoc < lengthLine) &&
(isspacechar(lineBuffer[cmdLoc]))) {
cmdLoc++;
}
SkipSpace(cmdLoc, lineBuffer);
// Colorize Pipe Operator
styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR);
styler.ColourTo(startLine + wordStart, SCE_BAT_OPERATOR);
// Reset Offset to re-process remainder of word
offset -= (wbl - 1);
offset = wordStart + 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) ))){
if ((AnyOf(first, '>', ')', '(', '&')) &&
!(!continueProcessing && (IsEscaped(lineBuffer, wordStart + wbo)
|| textQuoted(lineBuffer, wordStart)))){
// 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);
if ((!AnyOf(first, ')', '(')
&& !textQuoted(lineBuffer, wordStart) && !IsEscaped(lineBuffer, wordStart + wbo))
&& !((first == '=') && !isNotAssigned))
styler.ColourTo(startLine + wordStart, SCE_BAT_OPERATOR);
else
styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_DEFAULT);
styler.ColourTo(startLine + wordStart, SCE_BAT_DEFAULT);
// Reset Offset to re-process remainder of word
offset -= (wbl - 1);
offset = wordStart + 1;
if ((wordBuffer[0] == '=') && isNotAssigned ){
if ((first == '=') && 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++;
}
// Read up to %, !, Operator or Separator
const Sci_PositionU lengthWord = WordLength(word);
// Colorize Default Text
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT);
styler.ColourTo(startLine + wordStart + lengthWord - 1, SCE_BAT_DEFAULT);
// Reset Offset to re-process remainder of word
offset -= (wbl - wbo);
offset = wordStart + lengthWord;
}
// Skip next spaces - nothing happens if Offset was Reset
while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {
offset++;
}
SkipSpace(offset, lineBuffer);
}
// 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;
}
// Reset continueProcessing if line continuation was not found
continueProcessing = !IsContinuation(lineBuffer);
}
linePos = 0;
lineBuffer.clear();
startLine = i + 1;
}
}
styler.Flush();
}
const char *const batchWordListDesc[] = {
"Internal Commands",
"External Commands",
nullptr
};
}
extern const LexerModule lmBatch(SCLEX_BATCH, ColouriseBatchDoc, "batch", nullptr, batchWordListDesc);
extern const LexerModule lmBatch(SCLEX_LUA, LexerBatch::LexerFactoryBatch, "batch", batchWordListDesc);

View File

@ -388,6 +388,8 @@ constexpr Definition ParseDefine(std::string_view definition, std::string_view e
struct OptionsCPP {
bool stylingWithinPreprocessor = false;
bool identifiersAllowDollars = true;
bool identifiersAllowHashes = false;
bool enablePreprocessor = true;
bool trackPreprocessor = true;
bool updatePreprocessor = true;
bool verbatimStringsAllowEscapes = false;
@ -429,6 +431,12 @@ struct OptionSetCPP : public OptionSet<OptionsCPP> {
DefineProperty("lexer.cpp.allow.dollars", &OptionsCPP::identifiersAllowDollars,
"Set to 0 to disallow the '$' character in identifiers with the cpp lexer.");
DefineProperty("lexer.cpp.allow.hashes", &OptionsCPP::identifiersAllowHashes,
"Set to 1 to allow the '#' character in identifiers.");
DefineProperty("lexer.cpp.enable.preprocessor", &OptionsCPP::enablePreprocessor,
"Set to 0 to disable recognition of preprocessor directives.");
DefineProperty("lexer.cpp.track.preprocessor", &OptionsCPP::trackPreprocessor,
"Set to 1 to interpret #if/#else/#endif to grey out code that is not active.");
@ -729,11 +737,15 @@ public:
Sci_Position SCI_METHOD LexerCPP::PropertySet(const char *key, const char *val) {
if (osCPP.PropertySet(&options, key, val)) {
if (strcmp(key, "lexer.cpp.allow.dollars") == 0) {
const std::string_view keyView(key);
if ((keyView == "lexer.cpp.allow.dollars") || (keyView == "lexer.cpp.allow.hashes")) {
setWord = CharacterSet(CharacterSet::setAlphaNum, "._", true);
if (options.identifiersAllowDollars) {
setWord.Add('$');
}
if (options.identifiersAllowHashes) {
setWord.Add('#');
}
}
return 0;
}
@ -803,6 +815,9 @@ void SCI_METHOD LexerCPP::Lex(Sci_PositionU startPos, Sci_Position length, int i
if (options.identifiersAllowDollars) {
setWordStart.Add('$');
}
if (options.identifiersAllowHashes) {
setWordStart.Add('#');
}
int chPrevNonWhite = ' ';
int visibleChars = 0;
@ -1352,7 +1367,7 @@ void SCI_METHOD LexerCPP::Lex(Sci_PositionU startPos, Sci_Position length, int i
sc.SetState(SCE_C_STRING|activitySet);
} else if (sc.ch == '\'') {
sc.SetState(SCE_C_CHARACTER|activitySet);
} else if (sc.ch == '#' && visibleChars == 0) {
} else if (sc.ch == '#' && visibleChars == 0 && options.enablePreprocessor) {
// Preprocessor commands are alone on their line
sc.SetState(SCE_C_PREPROCESSOR|activitySet);
// Skip whitespace between # and preprocessor word

View File

@ -2467,7 +2467,7 @@ void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int
} else if (ch == '#' && cssContext == 0) {
styler.ColourTo(i - 1, StateToPrint);
state = SCE_HCSS_ID;
} else if (cssContext == 2 && (IsADigit(ch) || (ch == '-' && IsADigit(chNext)) || (ch == '.' && IsADigit(chNext)) || (ch == '#' && IsADigit(chNext, 16)))) {
} else if (cssContext == 2 && (IsADigit(ch) || (ch == '-' && IsADigit(chNext)) || (ch == '.' && IsADigit(chNext)) || (ch == '#' && IsAHeXDigit(chNext)))) {
styler.ColourTo(i - 1, StateToPrint);
state = SCE_HCSS_NUMBER;
} else if (cssContext == 2 && (IsAlphaNumeric(ch) || ch == '-' || ch == '_' || ch == '%')) {

View File

@ -57,6 +57,9 @@ const LexicalClass lexicalClasses[] = {
3, "SCE_MAKE_IDENTIFIER", "identifier", "Identifiers",
4, "SCE_MAKE_OPERATOR", "operator", "Operator",
5, "SCE_MAKE_TARGET", "identifier", "Identifiers",
6, "", "unused", "",
7, "", "unused", "",
8, "", "unused", "",
9, "SCE_MAKE_IDEOL", "error identifier", "Incomplete identifier reference",
};

View File

@ -34,11 +34,11 @@
*
*****************************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cstdio>
#include <cstdarg>
#include <string>
#include <string_view>
@ -63,11 +63,9 @@ constexpr bool IsNewline(const int ch) {
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) {
bool FollowToLineEnd(const int ch, const int state, const Sci_PositionU endPos, StyleContext &sc) {
Sci_Position i = 0;
while (sc.GetRelative(++i) == ch)
;
@ -79,12 +77,12 @@ static bool FollowToLineEnd(const int ch, const int state, const Sci_PositionU e
sc.Forward(i);
return true;
}
else return false;
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) {
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);
@ -105,7 +103,7 @@ static void SetStateAndZoom(const int state, const Sci_Position length, const in
}
// Does the previous line have more than spaces and tabs?
static bool HasPrevLineContent(StyleContext &sc) {
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)))
@ -120,11 +118,11 @@ static bool HasPrevLineContent(StyleContext &sc) {
return false;
}
static bool AtTermStart(StyleContext &sc) {
bool AtTermStart(const StyleContext &sc) noexcept {
return sc.currentPos == 0 || sc.chPrev == 0 || isspacechar(sc.chPrev);
}
static bool IsCompleteStyleRegion(StyleContext &sc, const char *token) {
bool IsCompleteStyleRegion(StyleContext &sc, const char *token) {
bool found = false;
const size_t start = strlen(token);
Sci_Position i = static_cast<Sci_Position>(start);
@ -140,12 +138,12 @@ static bool IsCompleteStyleRegion(StyleContext &sc, const char *token) {
return AtTermStart(sc) && found;
}
static bool IsValidHrule(const Sci_PositionU endPos, StyleContext &sc) {
bool IsValidHrule(const Sci_PositionU endPos, StyleContext &sc) {
int count = 1;
Sci_Position i = 0;
for (;;) {
++i;
int c = sc.GetRelative(i);
const int c = sc.GetRelative(i);
if (c == sc.ch)
++count;
// hit a terminating character
@ -158,17 +156,15 @@ static bool IsValidHrule(const Sci_PositionU endPos, StyleContext &sc) {
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
return true;
}
else {
sc.SetState(SCE_MARKDOWN_DEFAULT);
return false;
}
sc.SetState(SCE_MARKDOWN_DEFAULT);
return false;
}
}
}
static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList **, Accessor &styler) {
Sci_PositionU endPos = startPos + length;
const 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.
@ -178,7 +174,7 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
// property lexer.markdown.header.eolfill
// Set to 1 to highlight all ATX header text.
bool headerEOLFill = styler.GetPropertyInt("lexer.markdown.header.eolfill", 0) == 1;
const bool headerEOLFill = styler.GetPropertyInt("lexer.markdown.header.eolfill", 0) == 1;
StyleContext sc(startPos, static_cast<Sci_PositionU>(length), initStyle, styler);
@ -483,4 +479,6 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
sc.Complete();
}
}
extern const LexerModule lmMarkdown(SCLEX_MARKDOWN, ColorizeMarkdownDoc, "markdown");

View File

@ -110,15 +110,13 @@ contains requires
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <string>
#include <string_view>
#include <map>
#include "ILexer.h"
#include "Scintilla.h"
@ -130,32 +128,134 @@ contains requires
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "DefaultLexer.h"
using namespace Lexilla;
namespace {
void GetRangeLowered(Sci_PositionU start,
Sci_PositionU end,
Accessor &styler,
// Options used for LexerPascal
struct OptionsPascal {
bool bSmartHighlighting = true;
bool fold = false;
bool foldComment = false;
bool foldPreprocessor = false;
bool foldCompact = true;
};
const char *const pascalWordListDesc[] = {
"Keywords",
nullptr
};
struct OptionSetPascal : public OptionSet<OptionsPascal> {
OptionSetPascal() {
DefineProperty("lexer.pascal.smart.highlighting", &OptionsPascal::bSmartHighlighting,
"Set to 0 to not completely handle some complex features like 'property'.");
DefineProperty("fold", &OptionsPascal::fold);
DefineProperty("fold.comment", &OptionsPascal::foldComment);
DefineProperty("fold.preprocessor", &OptionsPascal::foldPreprocessor);
DefineProperty("fold.compact", &OptionsPascal::foldCompact);
DefineWordListSets(pascalWordListDesc);
}
};
const LexicalClass lexicalClasses[] = {
// Lexer pascal SCLEX_PASCAL SCE_PAS_
0, "SCE_PAS_DEFAULT", "default", "White space",
1, "SCE_PAS_IDENTIFIER", "identifier", "Identifier",
2, "SCE_PAS_COMMENT", "comment", "Comment: { ... }",
3, "SCE_PAS_COMMENT2", "comment", "Comment: (* ... *)",
4, "SCE_PAS_COMMENTLINE","comment line", "Line Comment: // ...",
5, "SCE_PAS_PREPROCESSOR", "preprocessor", "Preprocessor: {$ ... }",
6, "SCE_PAS_PREPROCESSOR2", "preprocessor", "Preprocessor: (*$ ... *)",
7, "SCE_PAS_NUMBER", "literal numeric", "Number",
8, "SCE_PAS_HEXNUMBER", "literal numeric", "Hex Number",
9, "SCE_PAS_WORD", "keyword", "Keyword",
10, "SCE_PAS_STRING", "literal string", "Single quoted string",
11, "SCE_PAS_STRINGEOL", "error literal string", "End of line where string is not closed",
12, "SCE_PAS_CHARACTER","literal string character", "Character",
13, "SCE_PAS_OPERATOR","operator", "Operator",
14, "SCE_PAS_ASM", "assembler", "Inline Assembler",
};
class LexerPascal : public DefaultLexer {
WordList keywords;
OptionsPascal options;
OptionSetPascal osPascal;
public:
explicit LexerPascal() :
DefaultLexer("pascal", SCLEX_PASCAL, lexicalClasses, std::size(lexicalClasses)) {
SetOptionSet(&osPascal);
}
LexerPascal(const LexerPascal &) = delete;
LexerPascal(LexerPascal &&) = delete;
LexerPascal &operator=(const LexerPascal &) = delete;
LexerPascal &operator=(LexerPascal &&) = delete;
~LexerPascal() override = default;
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, Scintilla::IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, Scintilla::IDocument *pAccess) override;
static ILexer5 *LexerFactoryPascal() {
return new LexerPascal();
}
};
Sci_Position SCI_METHOD LexerPascal::PropertySet(const char *key, const char *val) {
if (osPascal.PropertySet(&options, key, val)) {
return 0;
}
return -1;
}
Sci_Position SCI_METHOD LexerPascal::WordListSet(int n, const char *wl) {
WordList *wordListN = nullptr;
switch (n) {
case 0:
wordListN = &keywords;
break;
default:
break;
}
Sci_Position firstModification = -1;
if (wordListN) {
if (wordListN->Set(wl)) {
firstModification = 0;
}
}
return firstModification;
}
void GetRangeLowered(Sci_Position start,
Sci_Position end,
LexAccessor &styler,
char *s,
Sci_PositionU len) {
Sci_PositionU i = 0;
Sci_Position len) {
Sci_Position i = 0;
while ((i < end - start + 1) && (i < len-1)) {
s[i] = static_cast<char>(tolower(styler[start + i]));
s[i] = MakeLowerCase(styler[start + i]);
i++;
}
s[i] = '\0';
}
void GetForwardRangeLowered(Sci_PositionU start,
CharacterSet &charSet,
Accessor &styler,
void GetForwardRangeLowered(Sci_Position start,
const CharacterSet &charSet,
LexAccessor &styler,
char *s,
Sci_PositionU len) {
Sci_PositionU i = 0;
Sci_Position len) {
Sci_Position i = 0;
while ((i < len-1) && charSet.Contains(styler.SafeGetCharAt(start + i))) {
s[i] = static_cast<char>(tolower(styler.SafeGetCharAt(start + i)));
s[i] = MakeLowerCase(styler.SafeGetCharAt(start + i));
i++;
}
s[i] = '\0';
@ -172,9 +272,7 @@ enum {
stateFoldMaskAll = 0x0FFF
};
void ClassifyPascalWord(WordList *keywordlists[], StyleContext &sc, int &curLineState, bool bSmartHighlighting) {
WordList& keywords = *keywordlists[0];
void ClassifyPascalWord(const WordList &keywords, StyleContext &sc, int &curLineState, bool bSmartHighlighting) {
char s[100];
sc.GetCurrentLowered(s, sizeof(s));
if (keywords.InList(s)) {
@ -217,15 +315,14 @@ void ClassifyPascalWord(WordList *keywordlists[], StyleContext &sc, int &curLine
sc.SetState(SCE_PAS_DEFAULT);
}
void ColourisePascalDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
Accessor &styler) {
bool bSmartHighlighting = styler.GetPropertyInt("lexer.pascal.smart.highlighting", 1) != 0;
void LexerPascal::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, Scintilla::IDocument *pAccess) {
LexAccessor styler(pAccess);
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, "#$&'()*+,-./:;<=>@[]^{}");
const CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
const CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true);
const CharacterSet setNumber(CharacterSet::setDigits, ".-+eE");
const CharacterSet setHexNumber(CharacterSet::setDigits, "abcdefABCDEF");
const CharacterSet setOperator(CharacterSet::setNone, "#$&'()*+,-./:;<=>@[]^{}");
int curLineState = 0;
@ -248,7 +345,7 @@ void ColourisePascalDoc(Sci_PositionU startPos, Sci_Position length, int initSty
break;
case SCE_PAS_IDENTIFIER:
if (!setWord.Contains(sc.ch)) {
ClassifyPascalWord(keywordlists, sc, curLineState, bSmartHighlighting);
ClassifyPascalWord(keywords, sc, curLineState, options.bSmartHighlighting);
}
break;
case SCE_PAS_HEXNUMBER:
@ -294,7 +391,7 @@ void ColourisePascalDoc(Sci_PositionU startPos, Sci_Position length, int initSty
}
break;
case SCE_PAS_OPERATOR:
if (bSmartHighlighting && sc.chPrev == ';') {
if (options.bSmartHighlighting && sc.chPrev == ';') {
curLineState &= ~(stateInProperty | stateInExport);
}
sc.SetState(SCE_PAS_DEFAULT);
@ -341,23 +438,23 @@ void ColourisePascalDoc(Sci_PositionU startPos, Sci_Position length, int initSty
}
if (sc.state == SCE_PAS_IDENTIFIER && setWord.Contains(sc.chPrev)) {
ClassifyPascalWord(keywordlists, sc, curLineState, bSmartHighlighting);
ClassifyPascalWord(keywords, sc, curLineState, options.bSmartHighlighting);
}
sc.Complete();
}
bool IsStreamCommentStyle(int style) {
constexpr bool IsStreamCommentStyle(int style) noexcept {
return style == SCE_PAS_COMMENT || style == SCE_PAS_COMMENT2;
}
bool IsCommentLine(Sci_Position line, Accessor &styler) {
Sci_Position pos = styler.LineStart(line);
Sci_Position eolPos = styler.LineStart(line + 1) - 1;
bool IsCommentLine(Sci_Position line, LexAccessor &styler) {
const Sci_Position pos = styler.LineStart(line);
const 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);
const char ch = styler[i];
const char chNext = styler.SafeGetCharAt(i + 1);
const int style = styler.StyleIndexAt(i);
if (ch == '/' && chNext == '/' && style == SCE_PAS_COMMENTLINE) {
return true;
} else if (!IsASpaceOrTab(ch)) {
@ -367,18 +464,18 @@ bool IsCommentLine(Sci_Position line, Accessor &styler) {
return false;
}
unsigned int GetFoldInPreprocessorLevelFlag(int lineFoldStateCurrent) {
constexpr unsigned int GetFoldInPreprocessorLevelFlag(int lineFoldStateCurrent) noexcept {
return lineFoldStateCurrent & stateFoldInPreprocessorLevelMask;
}
void SetFoldInPreprocessorLevelFlag(int &lineFoldStateCurrent, unsigned int nestLevel) {
void SetFoldInPreprocessorLevelFlag(int &lineFoldStateCurrent, unsigned int nestLevel) noexcept {
lineFoldStateCurrent &= ~stateFoldInPreprocessorLevelMask;
lineFoldStateCurrent |= nestLevel & stateFoldInPreprocessorLevelMask;
}
void ClassifyPascalPreprocessorFoldPoint(int &levelCurrent, int &lineFoldStateCurrent,
Sci_PositionU startPos, Accessor &styler) {
CharacterSet setWord(CharacterSet::setAlpha);
Sci_Position startPos, LexAccessor &styler) {
const CharacterSet setWord(CharacterSet::setAlpha);
char s[11]; // Size of the longest possible keyword + one additional character + null
GetForwardRangeLowered(startPos, setWord, styler, s, sizeof(s));
@ -409,10 +506,10 @@ void ClassifyPascalPreprocessorFoldPoint(int &levelCurrent, int &lineFoldStateCu
}
}
Sci_PositionU SkipWhiteSpace(Sci_PositionU currentPos, Sci_PositionU endPos,
Accessor &styler, bool includeChars = false) {
CharacterSet setWord(CharacterSet::setAlphaNum, "_");
Sci_PositionU j = currentPos + 1;
Sci_Position SkipWhiteSpace(Sci_Position currentPos, Sci_Position endPos,
LexAccessor &styler, bool includeChars = false) {
const CharacterSet setWord(CharacterSet::setAlphaNum, "_");
Sci_Position j = currentPos + 1;
char ch = styler.SafeGetCharAt(j);
while ((j < endPos) && (IsASpaceOrTab(ch) || ch == '\r' || ch == '\n' ||
IsStreamCommentStyle(styler.StyleAt(j)) || (includeChars && setWord.Contains(ch)))) {
@ -423,8 +520,8 @@ Sci_PositionU SkipWhiteSpace(Sci_PositionU currentPos, Sci_PositionU endPos,
}
void ClassifyPascalWordFoldPoint(int &levelCurrent, int &lineFoldStateCurrent,
Sci_Position startPos, Sci_PositionU endPos,
Sci_PositionU lastStart, Sci_PositionU currentPos, Accessor &styler) {
Sci_Position startPos, Sci_Position endPos,
Sci_Position lastStart, Sci_Position currentPos, LexAccessor &styler) {
char s[100];
GetRangeLowered(lastStart, currentPos, styler, s, sizeof(s));
@ -439,10 +536,10 @@ void ClassifyPascalWordFoldPoint(int &levelCurrent, int &lineFoldStateCurrent,
} else if (strcmp(s, "class") == 0 || strcmp(s, "object") == 0) {
// "class" & "object" keywords require special handling...
bool ignoreKeyword = false;
Sci_PositionU j = SkipWhiteSpace(currentPos, endPos, styler);
Sci_Position j = SkipWhiteSpace(currentPos, endPos, styler);
if (j < endPos) {
CharacterSet setWordStart(CharacterSet::setAlpha, "_");
CharacterSet setWord(CharacterSet::setAlphaNum, "_");
const CharacterSet setWordStart(CharacterSet::setAlpha, "_");
const CharacterSet setWord(CharacterSet::setAlphaNum, "_");
if (styler.SafeGetCharAt(j) == ';') {
// Handle forward class declarations ("type TMyClass = class;")
@ -491,7 +588,7 @@ void ClassifyPascalWordFoldPoint(int &levelCurrent, int &lineFoldStateCurrent,
ignoreKeyword = false;
}
if (!ignoreKeyword) {
Sci_PositionU k = SkipWhiteSpace(currentPos, endPos, styler);
const Sci_Position k = SkipWhiteSpace(currentPos, endPos, styler);
if (k < endPos && styler.SafeGetCharAt(k) == ';') {
// Handle forward interface declarations ("type IMyInterface = interface;")
ignoreKeyword = true;
@ -503,7 +600,7 @@ void ClassifyPascalWordFoldPoint(int &levelCurrent, int &lineFoldStateCurrent,
} else if (strcmp(s, "dispinterface") == 0) {
// "dispinterface" keyword requires special handling...
bool ignoreKeyword = false;
Sci_PositionU j = SkipWhiteSpace(currentPos, endPos, styler);
const Sci_Position j = SkipWhiteSpace(currentPos, endPos, styler);
if (j < endPos && styler.SafeGetCharAt(j) == ';') {
// Handle forward dispinterface declarations ("type IMyInterface = dispinterface;")
ignoreKeyword = true;
@ -520,33 +617,44 @@ void ClassifyPascalWordFoldPoint(int &levelCurrent, int &lineFoldStateCurrent,
}
}
void FoldPascalDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[],
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;
void LexerPascal::Fold(Sci_PositionU startPos_, Sci_Position length, int initStyle, Scintilla::IDocument *pAccess) {
if (!options.fold)
return;
LexAccessor styler(pAccess);
Sci_Position startPos = startPos_;
const Sci_Position endPos = startPos + length;
Sci_Position lineCurrent = styler.GetLine(startPos);
// Backtrack to previous line in case need to fix its fold status
if (lineCurrent > 0) {
lineCurrent--;
startPos = styler.LineStart(lineCurrent);
initStyle = (startPos > 0) ? styler.StyleIndexAt(startPos - 1) : 0;
}
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 styleNext = styler.StyleIndexAt(startPos);
int style = initStyle;
int visibleChars = 0;
Sci_Position lastStart = 0;
CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true);
const CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true);
for (Sci_PositionU i = startPos; i < endPos; i++) {
char ch = chNext;
for (Sci_Position i = startPos; i < endPos; i++) {
const char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
int stylePrev = style;
const int stylePrev = style;
style = styleNext;
styleNext = styler.StyleAt(i + 1);
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
styleNext = styler.StyleIndexAt(i + 1);
const bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
if (foldComment && IsStreamCommentStyle(style)) {
if (options.foldComment && IsStreamCommentStyle(style)) {
if (!IsStreamCommentStyle(stylePrev)) {
levelCurrent++;
} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
@ -554,7 +662,7 @@ void FoldPascalDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, W
levelCurrent--;
}
}
if (foldComment && atEOL && IsCommentLine(lineCurrent, styler))
if (options.foldComment && atEOL && IsCommentLine(lineCurrent, styler))
{
if (!IsCommentLine(lineCurrent - 1, styler)
&& IsCommentLine(lineCurrent + 1, styler))
@ -563,7 +671,7 @@ void FoldPascalDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, W
&& !IsCommentLine(lineCurrent+1, styler))
levelCurrent--;
}
if (foldPreprocessor) {
if (options.foldPreprocessor) {
if (style == SCE_PAS_PREPROCESSOR && ch == '{' && chNext == '$') {
ClassifyPascalPreprocessorFoldPoint(levelCurrent, lineFoldStateCurrent, i + 2, styler);
} else if (style == SCE_PAS_PREPROCESSOR2 && ch == '(' && chNext == '*'
@ -588,14 +696,14 @@ void FoldPascalDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, W
if (atEOL) {
int lev = levelPrev;
if (visibleChars == 0 && foldCompact)
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);
}
int newLineState = (styler.GetLineState(lineCurrent) & ~stateFoldMaskAll) | lineFoldStateCurrent;
const int newLineState = (styler.GetLineState(lineCurrent) & ~stateFoldMaskAll) | lineFoldStateCurrent;
styler.SetLineState(lineCurrent, newLineState);
lineCurrent++;
levelPrev = levelCurrent;
@ -606,16 +714,11 @@ void FoldPascalDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, W
// 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)
if (visibleChars == 0 && options.foldCompact)
lev |= SC_FOLDLEVELWHITEFLAG;
styler.SetLevel(lineCurrent, lev);
}
const char * const pascalWordListDesc[] = {
"Keywords",
0
};
}
extern const LexerModule lmPascal(SCLEX_PASCAL, ColourisePascalDoc, "pascal", FoldPascalDoc, pascalWordListDesc);
extern const LexerModule lmPascal(SCLEX_PASCAL, LexerPascal::LexerFactoryPascal, "pascal", pascalWordListDesc);

View File

@ -454,16 +454,38 @@ const LexicalClass lexicalClasses[] = {
29, "SCE_PL_STRING_QR", "literal regex", "qr = regex",
30, "SCE_PL_STRING_QW", "literal string interpolated", "qw = array",
31, "SCE_PL_POD_VERB", "data", "pod: verbatim paragraphs",
32, "", "predefined", "",
33, "", "predefined", "",
34, "", "predefined", "",
35, "", "predefined", "",
36, "", "predefined", "",
37, "", "predefined", "",
38, "", "predefined", "",
39, "", "predefined", "",
40, "SCE_PL_SUB_PROTOTYPE", "identifier", "subroutine prototype",
41, "SCE_PL_FORMAT_IDENT", "identifier", "format identifier",
42, "SCE_PL_FORMAT", "literal string", "format body",
43, "SCE_PL_STRING_VAR", "identifier interpolated", "double quoted string (interpolated variable)",
44, "SCE_PL_XLAT", "literal string", "translation: tr{}{} y{}{}",
45, "", "unused", "",
46, "", "unused", "",
47, "", "unused", "",
48, "", "unused", "",
49, "", "unused", "",
50, "", "unused", "",
51, "", "unused", "",
52, "", "unused", "",
53, "", "unused", "",
54, "SCE_PL_REGEX_VAR", "identifier interpolated", "regex: /re/ or m{re} (interpolated variable)",
55, "SCE_PL_REGSUBST_VAR", "identifier interpolated", "substitution: s/re/ore/ (interpolated variable)",
56, "", "unused", "",
57, "SCE_PL_BACKTICKS_VAR", "identifier interpolated", "back ticks (interpolated variable)",
58, "", "unused", "",
59, "", "unused", "",
60, "", "unused", "",
61, "SCE_PL_HERE_QQ_VAR", "identifier interpolated", "here-doc (double quoted, qq) (interpolated variable)",
62, "SCE_PL_HERE_QX_VAR", "identifier interpolated", "here-doc (back ticks, qx) (interpolated variable)",
63, "", "unused", "",
64, "SCE_PL_STRING_QQ_VAR", "identifier interpolated", "qq = double quoted string (interpolated variable)",
65, "SCE_PL_STRING_QX_VAR", "identifier interpolated", "qx = back ticks (interpolated variable)",
66, "SCE_PL_STRING_QR_VAR", "identifier interpolated", "qr = regex (interpolated variable)",

View File

@ -147,6 +147,14 @@ const LexicalClass lexicalClasses[] = {
29, "SCE_RB_WORD_DEMOTED", "keyword", "Keyword demoted",
30, "SCE_RB_STDIN", "file", "Standard input stream",
31, "SCE_RB_STDOUT", "file", "Standard output stream",
32, "", "predefined", "",
33, "", "predefined", "",
34, "", "predefined", "",
35, "", "predefined", "",
36, "", "predefined", "",
37, "", "predefined", "",
38, "", "predefined", "",
39, "", "predefined", "",
40, "SCE_RB_STDERR", "file", "Standard error stream",
41, "SCE_RB_STRING_W", "literal string", "String array",
42, "SCE_RB_STRING_I", "literal string", "Symbol array",

View File

@ -60,7 +60,8 @@ int Accessor::IndentAmount(Sci_Position line, int *flags, PFNIsCommentLeader pfn
spaceFlags |= wsTab;
if (spaceFlags & wsSpace)
spaceFlags |= wsSpaceTab;
indent = (indent / 8 + 1) * 8;
constexpr int defaultTabSpaces = 8;
indent = (indent / defaultTabSpaces + 1) * defaultTabSpaces;
}
ch = (*this)[++pos];
}
@ -71,6 +72,5 @@ int Accessor::IndentAmount(Sci_Position line, int *flags, PFNIsCommentLeader pfn
if ((LineStart(line) == Length()) || (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') ||
(pfnIsCommentLeader && (*pfnIsCommentLeader)(*this, pos, end-pos)))
return indent | SC_FOLDLEVELWHITEFLAG;
else
return indent;
return indent;
}

View File

@ -4285,18 +4285,16 @@ bool IsIdContinue(int character) noexcept {
bool IsXidStart(int character) noexcept {
if (OmitXidStart(character)) {
return false;
} else {
return IsIdStart(character);
}
return IsIdStart(character);
}
// XID_Continue is ID_Continue modified for Normalization Form KC in UAX #31
bool IsXidContinue(int character) noexcept {
if (OmitXidContinue(character)) {
return false;
} else {
return IsIdContinue(character);
}
return IsIdContinue(character);
}
CharacterCategoryMap::CharacterCategoryMap() {

View File

@ -12,7 +12,9 @@ namespace Lexilla {
template<int N>
class CharacterSetArray {
unsigned char bset[(N-1)/8 + 1] = {};
static constexpr int bitsPerChar = 8;
static constexpr int mask3Bits = 7;
unsigned char bset[((N-1)/bitsPerChar) + 1] = {};
bool valueAfter = false;
public:
enum setBase {
@ -23,7 +25,7 @@ public:
setAlpha=setLower|setUpper,
setAlphaNum=setAlpha|setDigits
};
CharacterSetArray(setBase base=setNone, const char *initialSet="", bool valueAfter_=false) noexcept {
explicit CharacterSetArray(setBase base=setNone, const char *initialSet="", bool valueAfter_=false) noexcept {
valueAfter = valueAfter_;
AddString(initialSet);
if (base & setLower)
@ -33,7 +35,7 @@ public:
if (base & setDigits)
AddString("0123456789");
}
CharacterSetArray(const char *initialSet, bool valueAfter_=false) noexcept :
explicit CharacterSetArray(const char *initialSet, bool valueAfter_=false) noexcept :
CharacterSetArray(setNone, initialSet, valueAfter_) {
}
// For compatibility with previous version but should not be used in new code.
@ -44,7 +46,7 @@ public:
void Add(int val) noexcept {
assert(val >= 0);
assert(val < N);
bset[val >> 3] |= 1 << (val & 7);
bset[val >> 3] |= 1 << (val & mask3Bits);
}
void AddString(const char *setToAdd) noexcept {
for (const char *cp=setToAdd; *cp; cp++) {
@ -53,20 +55,21 @@ public:
Add(uch);
}
}
bool Contains(int val) const noexcept {
[[nodiscard]] bool Contains(int val) const noexcept {
assert(val >= 0);
if (val < 0) return false;
if (val >= N) return valueAfter;
return bset[val >> 3] & (1 << (val & 7));
return bset[val >> 3] & (1 << (val & mask3Bits));
}
bool Contains(char ch) const noexcept {
[[nodiscard]] bool Contains(char ch) const noexcept {
// Overload char as char may be signed
const unsigned char uch = ch;
return Contains(uch);
}
};
using CharacterSet = CharacterSetArray<0x80>;
constexpr int countASCII = 0x80;
using CharacterSet = CharacterSetArray<countASCII>;
// Functions for classifying characters
@ -84,8 +87,11 @@ constexpr void AnyOf([[maybe_unused]] T *t, [[maybe_unused]] Args... args) noexc
template <typename T, typename... Args>
constexpr void AnyOf([[maybe_unused]] const T *t, [[maybe_unused]] Args... args) noexcept {}
constexpr int charTab = 0x09;
constexpr int charCarriageReturn = 0x0D;
constexpr bool IsASpace(int ch) noexcept {
return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
return (ch == ' ') || ((ch >= charTab) && (ch <= charCarriageReturn));
}
constexpr bool IsASpaceOrTab(int ch) noexcept {
@ -107,17 +113,18 @@ constexpr bool IsAnOctalDigit(int ch) noexcept {
}
constexpr bool IsADigit(int ch, int base) noexcept {
if (base <= 10) {
constexpr int digits = 10;
if (base <= digits) {
return (ch >= '0') && (ch < '0' + base);
} else {
return ((ch >= '0') && (ch <= '9')) ||
((ch >= 'A') && (ch < 'A' + base - 10)) ||
((ch >= 'a') && (ch < 'a' + base - 10));
}
return ((ch >= '0') && (ch <= '9')) ||
((ch >= 'A') && (ch < 'A' + base - digits)) ||
((ch >= 'a') && (ch < 'a' + base - digits));
}
constexpr bool IsASCII(int ch) noexcept {
return (ch >= 0) && (ch < 0x80);
constexpr int lastASCII = 0x7F;
return (ch >= 0) && (ch <= lastASCII);
}
constexpr bool IsLowerCase(int ch) noexcept {
@ -144,7 +151,7 @@ constexpr bool IsAlphaNumeric(int ch) noexcept {
* This is ASCII specific but is safe with chars >= 0x80.
*/
constexpr bool isspacechar(int ch) noexcept {
return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
return (ch == ' ') || ((ch >= charTab) && (ch <= charCarriageReturn));
}
constexpr bool iswordchar(int ch) noexcept {
@ -174,16 +181,14 @@ template <typename T>
constexpr T MakeUpperCase(T ch) noexcept {
if (ch < 'a' || ch > 'z')
return ch;
else
return ch - 'a' + 'A';
return ch - 'a' + 'A';
}
template <typename T>
constexpr T MakeLowerCase(T ch) noexcept {
if (ch < 'A' || ch > 'Z')
return ch;
else
return ch - 'A' + 'a';
return ch - 'A' + 'a';
}
int CompareCaseInsensitive(const char *a, const char *b) noexcept;

View File

@ -11,6 +11,7 @@
#include <string>
#include <string_view>
#include <map>
#include "ILexer.h"
#include "Scintilla.h"
@ -21,6 +22,7 @@
#include "LexAccessor.h"
#include "Accessor.h"
#include "LexerModule.h"
#include "OptionSet.h"
#include "DefaultLexer.h"
using namespace Lexilla;
@ -46,14 +48,20 @@ int SCI_METHOD DefaultLexer::Version() const {
}
const char * SCI_METHOD DefaultLexer::PropertyNames() {
if (osi)
return osi->PropertyNames();
return "";
}
int SCI_METHOD DefaultLexer::PropertyType(const char *) {
int SCI_METHOD DefaultLexer::PropertyType(const char *name) {
if (osi)
return osi->PropertyType(name);
return SC_TYPE_BOOLEAN;
}
const char * SCI_METHOD DefaultLexer::DescribeProperty(const char *) {
const char * SCI_METHOD DefaultLexer::DescribeProperty(const char *name) {
if (osi)
return osi->DescribeProperty(name);
return "";
}
@ -62,6 +70,8 @@ Sci_Position SCI_METHOD DefaultLexer::PropertySet(const char *, const char *) {
}
const char * SCI_METHOD DefaultLexer::DescribeWordListSets() {
if (osi)
return osi->DescribeWordListSets();
return "";
}
@ -139,6 +149,8 @@ int SCI_METHOD DefaultLexer::GetIdentifier() {
return language;
}
const char *SCI_METHOD DefaultLexer::PropertyGet(const char * /* key */) {
const char *SCI_METHOD DefaultLexer::PropertyGet(const char *key) {
if (osi)
return osi->PropertyGet(key);
return nullptr;
}

View File

@ -12,16 +12,23 @@
namespace Lexilla {
struct OptionSetInterface; // Forward declaration
// A simple lexer with no state
class DefaultLexer : public Scintilla::ILexer5 {
const char *languageName;
int language;
const LexicalClass *lexClasses;
size_t nClasses;
OptionSetInterface *osi = nullptr;
public:
DefaultLexer(const char *languageName_, int language_,
const LexicalClass *lexClasses_ = nullptr, size_t nClasses_ = 0);
virtual ~DefaultLexer();
void SetOptionSet(OptionSetInterface *osi_) noexcept {
this->osi = osi_;
}
void SCI_METHOD Release() override;
int SCI_METHOD Version() const override;
const char * SCI_METHOD PropertyNames() override;

View File

@ -65,9 +65,8 @@ const char * SCI_METHOD LexerBase::DescribeProperty(const char *) {
Sci_Position SCI_METHOD LexerBase::PropertySet(const char *key, const char *val) {
if (props.Set(key, val)) {
return 0;
} else {
return -1;
}
return -1;
}
const char *SCI_METHOD LexerBase::PropertyGet(const char *key) {

View File

@ -17,7 +17,7 @@ protected:
size_t nClasses;
PropSetSimple props;
enum {numWordLists=KEYWORDSET_MAX+1};
WordList *keyWordLists[numWordLists+1];
WordList *keyWordLists[numWordLists+1]{};
public:
LexerBase(const LexicalClass *lexClasses_=nullptr, size_t nClasses_=0);
virtual ~LexerBase();

View File

@ -63,24 +63,22 @@ int LexerModule::GetLanguage() const noexcept {
int LexerModule::GetNumWordLists() const noexcept {
if (!wordListDescriptions) {
return -1;
} else {
int numWordLists = 0;
while (wordListDescriptions[numWordLists]) {
++numWordLists;
}
return numWordLists;
}
int numWordLists = 0;
while (wordListDescriptions[numWordLists]) {
++numWordLists;
}
return numWordLists;
}
const char *LexerModule::GetWordListDescription(int index) const noexcept {
assert(index < GetNumWordLists());
if (!wordListDescriptions || (index >= GetNumWordLists())) {
return "";
} else {
return wordListDescriptions[index];
}
return wordListDescriptions[index];
}
const LexicalClass *LexerModule::LexClasses() const noexcept {
@ -94,8 +92,7 @@ size_t LexerModule::NamedStyles() const noexcept {
Scintilla::ILexer5 *LexerModule::Create() const {
if (fnFactory)
return fnFactory();
else
return new LexerSimple(this);
return new LexerSimple(this);
}
void LexerModule::Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle,

View File

@ -12,12 +12,33 @@
namespace Lexilla {
inline std::string JoinWordListDescriptions(const char *const wordListDescriptions[]) {
std::string wordLists;
if (wordListDescriptions) {
for (size_t wl = 0; wordListDescriptions[wl]; wl++) {
if (wl > 0)
wordLists += "\n";
wordLists += wordListDescriptions[wl];
}
}
return wordLists;
}
// Allow OptionSet<T> to be called without knowing T
struct OptionSetInterface {
[[nodiscard]] virtual const char *PropertyNames() const noexcept = 0;
[[nodiscard]] virtual int PropertyType(const char *name) const = 0;
[[nodiscard]] virtual const char *DescribeProperty(const char *name) const = 0;
[[nodiscard]] virtual const char *PropertyGet(const char *name) const = 0;
[[nodiscard]] virtual const char *DescribeWordListSets() const noexcept = 0;
};
template <typename T>
class OptionSet {
typedef T Target;
typedef bool T::*plcob;
typedef int T::*plcoi;
typedef std::string T::*plcos;
class OptionSet : public OptionSetInterface {
using Target = T;
using plcob = bool T::*;
using plcoi = int T::*;
using plcos = std::string T::*;
struct Option {
int opType;
union {
@ -70,11 +91,11 @@ class OptionSet {
}
return false;
}
const char *Get() const noexcept {
[[nodiscard]] const char *Get() const noexcept {
return value.c_str();
}
};
typedef std::map<std::string, Option, std::less<>> OptionMap;
using OptionMap = std::map<std::string, Option, std::less<>> ;
OptionMap nameToDef;
std::string names;
std::string wordLists;
@ -85,6 +106,8 @@ class OptionSet {
names += name;
}
public:
virtual ~OptionSet() = default;
void DefineProperty(const char *name, plcob pb, std::string_view description="") {
nameToDef[name] = Option(pb, description);
AppendName(name);
@ -106,17 +129,17 @@ public:
nameToDef[name] = Option(pi, description);
AppendName(name);
}
const char *PropertyNames() const noexcept {
[[nodiscard]] const char *PropertyNames() const noexcept final {
return names.c_str();
}
int PropertyType(const char *name) const {
[[nodiscard]] int PropertyType(const char *name) const final {
typename OptionMap::const_iterator const it = nameToDef.find(name);
if (it != nameToDef.end()) {
return it->second.opType;
}
return SC_TYPE_BOOLEAN;
}
const char *DescribeProperty(const char *name) const {
[[nodiscard]] const char *DescribeProperty(const char *name) const final {
typename OptionMap::const_iterator const it = nameToDef.find(name);
if (it != nameToDef.end()) {
return it->second.description.c_str();
@ -132,7 +155,7 @@ public:
return false;
}
const char *PropertyGet(const char *name) const {
[[nodiscard]] const char *PropertyGet(const char *name) const final {
typename OptionMap::const_iterator const it = nameToDef.find(name);
if (it != nameToDef.end()) {
return it->second.Get();
@ -141,16 +164,10 @@ public:
}
void DefineWordListSets(const char * const wordListDescriptions[]) {
if (wordListDescriptions) {
for (size_t wl = 0; wordListDescriptions[wl]; wl++) {
if (wl > 0)
wordLists += "\n";
wordLists += wordListDescriptions[wl];
}
}
wordLists = JoinWordListDescriptions(wordListDescriptions);
}
const char *DescribeWordListSets() const noexcept {
[[nodiscard]] const char *DescribeWordListSets() const noexcept final {
return wordLists.c_str();
}
};

View File

@ -62,7 +62,7 @@ public:
}
}
bool Delete(Sci_Position position) {
typename stateVector::iterator low = Find(position);
const typename stateVector::iterator low = Find(position);
if (low != states.end()) {
states.erase(low, states.end());
return true;
@ -80,7 +80,7 @@ public:
bool different = true;
bool changed = false;
typename stateVector::iterator low = Find(other.positionFirst);
const typename stateVector::iterator low = Find(other.positionFirst);
if (static_cast<size_t>(states.end() - low) == other.states.size()) {
// Same number in other as after positionFirst in this
different = !std::equal(low, states.end(), other.states.begin());

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python3
# LexillaData.py - implemented 2013 by Neil Hodgson neilh@scintilla.org
# Released to the public domain.
# Requires FileGenerator from Scintilla so scintilla must be a peer directory of lexilla.
"""
Common code used by Lexilla and SciTE for source file regeneration.
@ -59,7 +58,7 @@ def FindModules(lexFile):
partLine = ""
with lexFile.open(encoding=neutralEncoding) as f:
lineNum = 0
for line in f.readlines():
for line in f:
lineNum += 1
line = line.rstrip()
if partLine or line.startswith("extern const LexerModule"):
@ -162,7 +161,7 @@ def FindProperties(lexFile):
""" Return a set of property names in a lexer implementation file. """
properties = set()
with open(lexFile, encoding=neutralEncoding) as f:
for s in f.readlines():
for s in f:
if ("GetProperty" in s or "DefineProperty" in s) and "\"" in s:
s = s.strip()
if not s.startswith("//"): # Drop comments
@ -180,7 +179,7 @@ def FindPropertyDocumentation(lexFile):
documents = {}
with lexFile.open(encoding=neutralEncoding) as f:
name = ""
for line in f.readlines():
for line in f:
line = line.strip()
if "// property " in line:
propertyName = line.split()[2]
@ -219,19 +218,19 @@ def FindPropertyDocumentation(lexFile):
def FindCredits(historyFile):
""" Return a list of contributors in a history file. """
creditList = []
credits = []
stage = 0
with historyFile.open(encoding="utf-8") as f:
for line in f.readlines():
line = line.strip()
if stage == 0 and line == "<table>":
for line in f:
s = line.strip()
if stage == 0 and s == "<table>":
stage = 1
elif stage == 1 and line == "</table>":
elif stage == 1 and s == "</table>":
stage = 2
if stage == 1 and line.startswith("<td>"):
credit = line[4:-5]
if "<a" in line:
title, dummy, rest = credit.partition("<a href=")
if stage == 1 and s.startswith("<td>"):
credit = s[4:-5]
if "<a" in s:
title, _, rest = credit.partition("<a href=")
urlplus, _bracket, end = rest.partition(">")
name = end.split("<")[0]
url = urlplus[1:-1]
@ -239,8 +238,8 @@ def FindCredits(historyFile):
if credit:
credit += " "
credit += name + " " + url
creditList.append(credit)
return creditList
credits.append(credit)
return credits
def ciKey(a):
""" Return a string lowered to be used when sorting. """
@ -261,7 +260,7 @@ class LexillaData:
self.versionCommad = self.versionDotted.replace(".", ", ") + ', 0'
with (scintillaRoot / "doc" / "Lexilla.html").open() as f:
self.dateModified = [d for d in f.readlines() if "Date.Modified" in d]\
self.dateModified = [d for d in f if "Date.Modified" in d]\
[0].split('\"')[3]
# 20130602
# Lexilla.html

View File

@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>5.4.7</string>
<string>5.4.8</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>

View File

@ -900,7 +900,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5.4.7;
CURRENT_PROJECT_VERSION = 5.4.8;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 4F446KW87E;
DYLIB_COMPATIBILITY_VERSION = 1;
@ -928,7 +928,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5.4.7;
CURRENT_PROJECT_VERSION = 5.4.8;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 4F446KW87E;
DYLIB_COMPATIBILITY_VERSION = 1;

View File

@ -4,8 +4,8 @@
#include <windows.h>
#define VERSION_LEXILLA "5.4.7"
#define VERSION_WORDS 5, 4, 7, 0
#define VERSION_LEXILLA "5.4.8"
#define VERSION_WORDS 5, 4, 8, 0
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_WORDS

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
547
548

View File

@ -26,9 +26,9 @@
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
<tr>
<td>
<font size="4"> <a href="https://www.scintilla.org/scintilla560.zip">
<font size="4"> <a href="https://www.scintilla.org/scintilla561.zip">
Windows</a>&nbsp;&nbsp;
<a href="https://www.scintilla.org/scintilla560.tgz">
<a href="https://www.scintilla.org/scintilla561.tgz">
GTK/Linux</a>&nbsp;&nbsp;
</font>
</td>
@ -42,7 +42,7 @@
containing very few restrictions.
</p>
<h3>
Release 5.6.0
Release 5.6.1
</h3>
<h4>
Source Code
@ -50,8 +50,8 @@
The source code package contains all of the source code for Scintilla but no binary
executable code and is available in
<ul>
<li><a href="https://www.scintilla.org/scintilla560.zip">zip format</a> (1.8M) commonly used on Windows</li>
<li><a href="https://www.scintilla.org/scintilla560.tgz">tgz format</a> (1.7M) commonly used on Linux and compatible operating systems</li>
<li><a href="https://www.scintilla.org/scintilla561.zip">zip format</a> (1.8M) commonly used on Windows</li>
<li><a href="https://www.scintilla.org/scintilla561.tgz">tgz format</a> (1.7M) 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>

View File

@ -603,7 +603,7 @@
</h3>
<ul>
<li>
Released 25 February 2026.
Released 26 March 2026.
</li>
<li>
Add mode to draw tabs as [HT] blobs with SCI_SETTABDRAWMODE(SCTD_CONTROLCHAR).

View File

@ -9,7 +9,7 @@
<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="20260225" />
<meta name="Date.Modified" content="20260326" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
.logo {
@ -61,8 +61,8 @@
GTK, and macOS</font>
</td>
<td width="40%" align="right">
<font color="#FFCC99" size="3"> Release version 5.6.0<br />
Site last modified February 25 2026</font>
<font color="#FFCC99" size="3"> Release version 5.6.1<br />
Site last modified March 26 2026</font>
</td>
<td width="20%">
&nbsp;
@ -77,12 +77,11 @@
</tr>
</table>
<ul id="versionlist">
<li>Version 5.6.1 adds mode to draw tabs as HT blobs and fixes a regression in SCI_CONVERTEOLS.</li>
<li>Version 5.6.0 fixes crash when window is too narrow to show any text.</li>
<li>Version 5.5.9 adds an option to disable drag &amp; drop. Fixes colour after line end.</li>
<li>Version 5.5.8 changes format of SCI_GETSELECTIONSERIALIZED and fixes redraw after undo.</li>
<li>Version 5.5.7 can prevent storing scroll position in undo selection history and adds a wrap-aware SCI_SCROLLVERTICAL API.</li>
<li>Version 5.5.6 improves DBCS and autocompletion drawing on Win32 and improves dwell, encoding and text clipping on Qt.</li>
<li>Version 5.5.5 can remember selection with undo and redo. Update to use DirectWrite 1.1.</li>
</ul>
<ul id="menu">
<li id="remote1"><a href="https://www.scintilla.org/SciTEImage.html">Screenshot</a></li>

View File

@ -35,13 +35,13 @@ def depunctuate(s):
symbols = {}
with open(incFileName, "rt") as incFile:
for line in incFile.readlines():
for line in incFile:
if line.startswith("#define"):
identifier = line.split()[1]
symbols[identifier] = 0
with open(docFileName, "rt") as docFile:
for line in docFile.readlines():
for line in docFile:
for word in depunctuate(line).split():
if word in symbols.keys():
symbols[word] = 1

View File

@ -17,9 +17,10 @@
# Only tested with ASCII file names.
# Copyright 2019 by Neil Hodgson <neilh@scintilla.org>
# The License.txt file describes the conditions under which this software may be distributed.
# Requires Python 2.7 or later
# Requires Python 3.6 or later
import codecs, glob, os, sys
from functools import cache
if __name__ == "__main__":
import FileGenerator
@ -28,6 +29,7 @@ else:
continuationLineEnd = " \\"
@cache
def FindPathToHeader(header, includePath):
for incDir in includePath:
relPath = os.path.join(incDir, header)
@ -35,27 +37,25 @@ def FindPathToHeader(header, includePath):
return relPath
return ""
fhifCache = {} # Remember the includes in each file. ~5x speed up.
@cache
def FindHeadersInFile(filePath):
if filePath not in fhifCache:
headers = []
with codecs.open(filePath, "r", "utf-8") as f:
for line in f:
if line.strip().startswith("#include"):
parts = line.split()
if len(parts) > 1:
header = parts[1]
if header[0] != '<': # No system headers
headers.append(header.strip('"'))
fhifCache[filePath] = headers
return fhifCache[filePath]
headers = []
with codecs.open(filePath, "r", "utf-8") as f:
for line in f:
if line.strip().startswith("#include"):
parts = line.split()
if len(parts) > 1:
header = parts[1]
if header[0] != '<': # No system headers
headers.append(header.strip('"'))
return headers
def FindHeadersInFileRecursive(filePath, includePath, renames):
headerPaths = []
for header in FindHeadersInFile(filePath):
if header in renames:
header = renames[header]
relPath = FindPathToHeader(header, includePath)
relPath = FindPathToHeader(header, tuple(includePath))
if relPath and relPath not in headerPaths:
headerPaths.append(relPath)
subHeaders = FindHeadersInFileRecursive(relPath, includePath, renames)

View File

@ -2,7 +2,7 @@
# Face.py - module for reading and parsing Scintilla.iface file
# Implemented 2000 by Neil Hodgson neilh@scintilla.org
# Released to the public domain.
# Requires Python 2.7 or later
# Requires Python 3.6 or later
def sanitiseLine(line):
line = line.rstrip('\n')
@ -72,7 +72,7 @@ class Face:
currentComment = []
currentCommentFinished = 0
file = open(name)
for line in file.readlines():
for line in file:
line = sanitiseLine(line)
if line:
if line[0] == "#":

View File

@ -4,7 +4,7 @@
# Generate or regenerate source files based on comments in those files.
# May be modified in-place or a template may be generated into a complete file.
# Requires Python 2.7 or later
# Requires Python 3.6 or later
# The files are copied to a string apart from sections between a
# ++Autogenerated comment and a --Autogenerated comment which is
# generated by the CopyWithInsertion function. After the whole string is
@ -143,7 +143,7 @@ def UpdateLineInPlistFile(path, key, value):
lines = []
keyCurrent = ""
with codecs.open(path, "rb", "utf-8") as f:
for line in f.readlines():
for line in f:
ls = line.strip()
if ls.startswith("<key>"):
keyCurrent = ls.replace("<key>", "").replace("</key>", "")
@ -160,7 +160,7 @@ def UpdateLineInFile(path, linePrefix, lineReplace):
lines = []
updated = False
with codecs.open(path, "r", "utf-8") as f:
for line in f.readlines():
for line in f:
line = line.rstrip()
if not updated and line.startswith(linePrefix):
lines.append(lineReplace)

View File

@ -2,7 +2,7 @@
# Script to generate scintilla/src/CharacterCategoryMap.cxx and lexilla/lexlib/CharacterCategory.cxx
# from Python's Unicode data
# Should be run rarely when a Python with a new version of Unicode data is available.
# Requires Python 3.3 or later
# Requires Python 3.6 or later
# Should not be run with old versions of Python.
import pathlib, platform, sys, unicodedata
@ -11,7 +11,7 @@ from FileGenerator import Regenerate
def findCategories(filename):
with filename.open(encoding="UTF-8") as infile:
lines = [x.strip() for x in infile.readlines() if "\tcc" in x]
lines = [x.strip() for x in infile if "\tcc" in x]
values = "".join(lines).replace(" ","").split(",")
print("Categrories:", values)
return [v[2:] for v in values]

View File

@ -25,19 +25,20 @@
import datetime, pathlib, sys
def FindCredits(historyFile, removeLinks=True):
""" Return a list of contributors in a history file. """
credits = []
stage = 0
with historyFile.open(encoding="utf-8") as f:
for line in f.readlines():
line = line.strip()
if stage == 0 and line == "<table>":
for line in f:
s = line.strip()
if stage == 0 and s == "<table>":
stage = 1
elif stage == 1 and line == "</table>":
elif stage == 1 and s == "</table>":
stage = 2
if stage == 1 and line.startswith("<td>"):
credit = line[4:-5]
if removeLinks and "<a" in line:
title, _a, rest = credit.partition("<a href=")
if stage == 1 and s.startswith("<td>"):
credit = s[4:-5]
if removeLinks and "<a" in s:
title, _, rest = credit.partition("<a href=")
urlplus, _bracket, end = rest.partition(">")
name = end.split("<")[0]
url = urlplus[1:-1]
@ -57,14 +58,14 @@ class ScintillaData:
self.versionCommad = self.versionDotted.replace(".", ", ") + ', 0'
with (scintillaRoot / "doc" / "index.html").open() as f:
self.dateModified = [d for d in f.readlines() if "Date.Modified" in d]\
self.dateModified = [d for d in f if "Date.Modified" in d]\
[0].split('\"')[3]
# 20130602
# index.html, SciTE.html
dtModified = datetime.datetime.strptime(self.dateModified, "%Y%m%d")
self.yearModified = self.dateModified[0:4]
monthModified = dtModified.strftime("%B")
dayModified = "%d" % dtModified.day
dayModified = f"{dtModified.day}"
self.mdyModified = monthModified + " " + dayModified + " " + self.yearModified
# May 22 2013
# index.html, SciTE.html

View File

@ -1 +1 @@
560
561

View File

@ -6,8 +6,8 @@
#include <windows.h>
#define VERSION_SCINTILLA "5.6.0"
#define VERSION_WORDS 5, 6, 0, 0
#define VERSION_SCINTILLA "5.6.1"
#define VERSION_WORDS 5, 6, 1, 0
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_WORDS