Update to scintilla 5.5.1 & Lexilla 5.3.3

Release 5.5.1 ( https://www.scintilla.org/scintilla551.zip )

    Released 22 July 2024.
    SCI_CUTALLOWLINE added which is similar to SCI_COPYALLOWLINE but also deletes the copied text. Feature #1518.
    Can set font used for autocompletion lists with SCI_AUTOCSETSTYLE. Feature #1523.
    Increase maximum zoom set interactively to +60 points. Feature #1517.
    Fix flickering cursor after some mouse action sequences. Bug #2443.

Release 5.3.3 ( https://www.scintilla.org/lexilla533.zip )

    Released 22 July 2024.
    ASP: Control whether ASP is enabled for XML and HTML with lexer.xml.allow.asp and lexer.html.allow.asp. Issue #252.
    JavaScript: Recognize regular expressions at start or after '>' in JavaScript when lexer is cpp, hypertext, or xml. Issue #250, Bug #918.
    JavaScript: Recognize initial #! 'shebang' line as a comment in standalone files. Issue #253.
    Lua: Fix non-ASCII identifiers joined with '.' or ':'. Issue #242.
    Lua: Fix folding for multi-line SCE_LUA_LITERALSTRING and SCE_LUA_COMMENT when performed incrementally. Issue #247.
    PHP: Control whether PHP is enabled for XML and HTML with lexer.xml.allow.php and lexer.html.allow.php. Issue #252.

Close #15466
This commit is contained in:
Christian Grasser 2024-07-22 22:36:53 +02:00 committed by Don Ho
parent d805dcb39c
commit d8c6350918
83 changed files with 1024 additions and 475 deletions

View File

@ -5,7 +5,7 @@ on: [push]
jobs:
build:
runs-on: macos-11
runs-on: macos-latest
strategy:
matrix:
@ -18,16 +18,16 @@ jobs:
(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)
run: (cd test/unit && make DEBUG=1 CXX=${{matrix.cpp_compiler}} --jobs=$(getconf _NPROCESSORS_ONLN) test)
- name: Build Lexilla
run: (cd src && make DEBUG=1 CXX=${{matrix.cpp_compiler}})
run: (cd src && make DEBUG=1 CXX=${{matrix.cpp_compiler}} --jobs=$(getconf _NPROCESSORS_ONLN))
- 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)
run: (cd test && make DEBUG=1 CXX=${{matrix.cpp_compiler}} --jobs=$(getconf _NPROCESSORS_ONLN) test)
- name: CheckLexilla C Example
run: (cd examples/CheckLexilla && make DEBUG=1 check)
run: (cd examples/CheckLexilla && make DEBUG=1 --jobs=$(getconf _NPROCESSORS_ONLN) check)
- name: SimpleLexer Example
run: (cd examples/SimpleLexer && make DEBUG=1 CXX=${{matrix.cpp_compiler}} check)
run: (cd examples/SimpleLexer && make DEBUG=1 CXX=${{matrix.cpp_compiler}} --jobs=$(getconf _NPROCESSORS_ONLN) check)

View File

@ -43,11 +43,11 @@ jobs:
- name: CheckLexilla C Example
run: |
cd examples/CheckLexilla
cl CheckLexilla.c -I ../../include -Fe: CheckLexilla
cl -MP 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
cl -MP -std:c++17 -EHsc -LD -I ../../../scintilla/include -I ../../include -I ../../lexlib SimpleLexer.cxx ../../lexlib/*.cxx
cd ../..

View File

@ -18,17 +18,17 @@ jobs:
(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)
run: (cd test/unit && make DEBUG=1 CXX=${{matrix.cpp_compiler}} --jobs=$(getconf _NPROCESSORS_ONLN) test)
- name: Build Lexilla
run: (cd src && make DEBUG=1 CXX=${{matrix.cpp_compiler}})
run: (cd src && make DEBUG=1 CXX=${{matrix.cpp_compiler}} --jobs=$(getconf _NPROCESSORS_ONLN))
- 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)
run: (cd test && make DEBUG=1 CXX=${{matrix.cpp_compiler}} --jobs=$(getconf _NPROCESSORS_ONLN) test)
- name: CheckLexilla C Example
run: (cd examples/CheckLexilla && make DEBUG=1 check)
run: (cd examples/CheckLexilla && make DEBUG=1 --jobs=$(getconf _NPROCESSORS_ONLN) check)
- name: SimpleLexer Example
run: (cd examples/SimpleLexer && make DEBUG=1 CXX=${{matrix.cpp_compiler}} check)
run: (cd examples/SimpleLexer && make DEBUG=1 CXX=${{matrix.cpp_compiler}} --jobs=$(getconf _NPROCESSORS_ONLN) check)

View File

@ -11,6 +11,9 @@ useInitializationList
// produces same result on empty collections
useStlAlgorithm
// Common for lexer object destructors
missingOverride
// Some non-explicit constructors are used for conversions or are private to lexers
noExplicitConstructor
@ -153,7 +156,6 @@ 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
@ -205,3 +207,9 @@ knownConditionTrueFalse:lexilla/test/unit/testCharacterSet.cxx
// cppcheck fails REQUIRE from Catch
comparisonOfFuncReturningBoolError:lexilla/test/unit/*.cxx
// cppcheck fails SECTION from Catch
syntaxError:lexilla/test/unit/*.cxx
// argv has a standardised type
constParameter:lexilla/examples/CheckLexilla/CheckLexilla.c

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="20240423" />
<meta name="Date.Modified" content="20240722" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
.logo {
@ -61,8 +61,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.3.2<br />
Site last modified April 23 2024</font>
<font color="#FFCC99" size="3">Release version 5.3.3<br />
Site last modified July 22 2024</font>
</td>
<td width="20%">
&nbsp;
@ -77,11 +77,11 @@
</tr>
</table>
<ul id="versionlist">
<li>Version 5.3.3 improves HTML, JavaScript, Lua, PHP, and XML.</li>
<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>

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/lexilla532.zip">
<font size="4"> <a href="https://www.scintilla.org/lexilla533.zip">
Windows</a>&nbsp;&nbsp;
<a href="https://www.scintilla.org/lexilla532.tgz">
<a href="https://www.scintilla.org/lexilla533.tgz">
GTK/Linux</a>&nbsp;&nbsp;
</font>
</td>
@ -42,7 +42,7 @@
containing very few restrictions.
</p>
<h3>
Release 5.3.2
Release 5.3.3
</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/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>
<li><a href="https://www.scintilla.org/lexilla533.zip">zip format</a> (1.3M) commonly used on Windows</li>
<li><a href="https://www.scintilla.org/lexilla533.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>

View File

@ -588,6 +588,43 @@
</tr>
</table>
<h2>Releases</h2>
<h3>
<a href="https://www.scintilla.org/lexilla533.zip">Release 5.3.3</a>
</h3>
<ul>
<li>
Released 22 July 2024.
</li>
<li>
ASP: Control whether ASP is enabled for XML and HTML with
lexer.xml.allow.asp and lexer.html.allow.asp.
<a href="https://github.com/ScintillaOrg/lexilla/issues/252">Issue #252</a>.
</li>
<li>
JavaScript: Recognize regular expressions at start or after '&gt;' in JavaScript when lexer is cpp,
hypertext, or xml.
<a href="https://github.com/ScintillaOrg/lexilla/issues/250">Issue #250</a>,
<a href="https://sourceforge.net/p/scintilla/bugs/918/">Bug #918</a>.
</li>
<li>
JavaScript: Recognize initial #! 'shebang' line as a comment in standalone files.
<a href="https://github.com/ScintillaOrg/lexilla/issues/253">Issue #253</a>.
</li>
<li>
Lua: Fix non-ASCII identifiers joined with '.' or ':'.
<a href="https://github.com/ScintillaOrg/lexilla/issues/242">Issue #242</a>.
</li>
<li>
Lua: Fix folding for multi-line SCE_LUA_LITERALSTRING and SCE_LUA_COMMENT
when performed incrementally.
<a href="https://github.com/ScintillaOrg/lexilla/issues/247">Issue #247</a>.
</li>
<li>
PHP: Control whether PHP is enabled for XML and HTML with
lexer.xml.allow.php and lexer.html.allow.php.
<a href="https://github.com/ScintillaOrg/lexilla/issues/252">Issue #252</a>.
</li>
</ul>
<h3>
<a href="https://www.scintilla.org/lexilla532.zip">Release 5.3.2</a>
</h3>

View File

@ -2,14 +2,15 @@
INCLUDES = -I ../../../scintilla/include -I ../../include -I ../../lexlib
BASE_FLAGS += --std=c++17 -shared
BASE_FLAGS += --std=c++17
ifdef windir
SHAREDEXTENSION = dll
else
ifeq ($(shell uname),Darwin)
SHAREDEXTENSION = dylib
BASE_FLAGS += -dynamiclib -arch arm64 -arch x86_64
BASE_FLAGS += -arch arm64 -arch x86_64
LINK_FLAGS += -dynamiclib
else
BASE_FLAGS += -fPIC
SHAREDEXTENSION = so
@ -23,7 +24,14 @@ ifdef windir
endif
LIBRARY = SimpleLexer.$(SHAREDEXTENSION)
LEXLIB = ../../lexlib/*.cxx
vpath %.cxx ../../lexlib
LEXLIB_SOURCES := $(sort $(notdir $(wildcard ../../lexlib/*.cxx)))
LEXLIB = $(LEXLIB_SOURCES:.cxx=.o)
%.o: %.cxx
$(CXX) $(INCLUDES) $(BASE_FLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
all: $(LIBRARY)
@ -34,5 +42,5 @@ check: $(LIBRARY)
clean:
$(RM) *.o *obj *.lib *.exp $(LIBRARY)
$(LIBRARY): *.cxx
$(CXX) $(INCLUDES) $(BASE_FLAGS) $(CPPFLAGS) $(CXXFLAGS) $^ $(LEXLIB) $(LIBS) $(LDLIBS) -o $@
$(LIBRARY): $(LEXLIB) *.cxx
$(CXX) $(INCLUDES) $(LINK_FLAGS) $(BASE_FLAGS) -shared $(CPPFLAGS) $(CXXFLAGS) $^ $(LIBS) $(LDLIBS) -o $@

View File

@ -791,7 +791,7 @@ void SCI_METHOD LexerCPP::Lex(Sci_PositionU startPos, Sci_Position length, int i
const StyleContext::Transform transform = caseSensitive ?
StyleContext::Transform::none : StyleContext::Transform::lower;
const CharacterSet setOKBeforeRE("([{=,:;!%^&*|?~+-");
const CharacterSet setOKBeforeRE("([{=,:;!%^&*|?~+-> ");
const CharacterSet setCouldBePostOp("+-");
const CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]");
@ -890,6 +890,12 @@ void SCI_METHOD LexerCPP::Lex(Sci_PositionU startPos, Sci_Position length, int i
Sci_PositionU lineEndNext = styler.LineEnd(lineCurrent);
if (sc.currentPos == 0 && sc.Match('#', '!')) {
// Shell Shebang at beginning of file
sc.SetState(SCE_C_COMMENTLINE);
sc.Forward();
}
for (; sc.More();) {
if (sc.atLineStart) {

View File

@ -28,10 +28,12 @@
#include "LexerModule.h"
/***************************************/
#if defined(__clang__) && !defined(__APPLE__)
#if defined(__clang__)
#if __has_warning("-Wunused-but-set-variable")
// Disable warning for numNonBlank
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#endif
#endif
using namespace Lexilla;

View File

@ -675,6 +675,30 @@ constexpr bool isPHPStringState(int state) noexcept {
(state == SCE_HPHP_COMPLEX_VARIABLE);
}
enum class AllowPHP : int {
None, // No PHP
PHP, // <?php and <?=
Question, // <?
};
constexpr bool IsPHPEntryState(int state) noexcept {
return !(isPHPStringState(state) || IsScriptCommentState(state) || AnyOf(state, SCE_H_ASPAT, SCE_HPHP_COMMENT, SCE_HPHP_COMMENTLINE));
}
bool IsPHPStart(AllowPHP allowPHP, Accessor &styler, Sci_PositionU start) {
if (allowPHP == AllowPHP::None) {
return false;
}
if (allowPHP == AllowPHP::PHP) {
// Require <?php or <?=
constexpr std::string_view phpTag = "<?php";
constexpr std::string_view echoTag = "<?=";
const std::string tag = styler.GetRangeLowered(start, start + phpTag.length());
return (tag == phpTag) || (tag.substr(0, echoTag.length()) == echoTag);
}
return true;
}
Sci_Position FindPhpStringDelimiter(std::string &phpStringDelimiter, Sci_Position i, const Sci_Position lengthDoc, Accessor &styler, bool &isSimpleString) {
const Sci_Position beginning = i - 1;
bool isQuoted = false;
@ -722,8 +746,12 @@ struct OptionsHTML {
int aspDefaultLanguage = eScriptJS;
bool caseSensitive = false;
bool allowScripts = true;
AllowPHP allowPHPinXML = AllowPHP::Question;
AllowPHP allowPHPinHTML = AllowPHP::Question;
bool isMako = false;
bool isDjango = false;
bool allowASPinXML = true;
bool allowASPinHTML = true;
bool fold = false;
bool foldHTML = false;
bool foldHTMLPreprocessor = true;
@ -767,12 +795,26 @@ struct OptionSetHTML : public OptionSet<OptionsHTML> {
DefineProperty("lexer.xml.allow.scripts", &OptionsHTML::allowScripts,
"Set to 0 to disable scripts in XML.");
DefineProperty("lexer.xml.allow.php", &OptionsHTML::allowPHPinXML,
"Set to 0 to disable PHP in XML, 1 to accept <?php and <?=, 2 to also accept <?."
"The default is 2.");
DefineProperty("lexer.html.allow.php", &OptionsHTML::allowPHPinHTML,
"Set to 0 to disable PHP in HTML, 1 to accept <?php and <?=, 2 to also accept <?."
"The default is 2.");
DefineProperty("lexer.html.mako", &OptionsHTML::isMako,
"Set to 1 to enable the mako template language.");
DefineProperty("lexer.html.django", &OptionsHTML::isDjango,
"Set to 1 to enable the django template language.");
DefineProperty("lexer.xml.allow.asp", &OptionsHTML::allowASPinXML,
"Set to 0 to disable ASP in XML.");
DefineProperty("lexer.html.allow.asp", &OptionsHTML::allowASPinHTML,
"Set to 0 to disable ASP in HTML.");
DefineProperty("fold", &OptionsHTML::fold);
DefineProperty("fold.html", &OptionsHTML::foldHTML,
@ -1219,13 +1261,15 @@ void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int
const bool foldXmlAtTagOpen = isXml && fold && options.foldXmlAtTagOpen;
const bool caseSensitive = options.caseSensitive;
const bool allowScripts = options.allowScripts;
const AllowPHP allowPHP = isXml ? options.allowPHPinXML : options.allowPHPinHTML;
const bool isMako = options.isMako;
const bool isDjango = options.isDjango;
const bool allowASP = (isXml ? options.allowASPinXML : options.allowASPinHTML) && !isMako && !isDjango;
const CharacterSet setHTMLWord(CharacterSet::setAlphaNum, ".-_:!#", true);
const CharacterSet setTagContinue(CharacterSet::setAlphaNum, ".-_:!#[", true);
const CharacterSet setAttributeContinue(CharacterSet::setAlphaNum, ".-_:!#/", true);
// TODO: also handle + and - (except if they're part of ++ or --) and return keywords
const CharacterSet setOKBeforeJSRE(CharacterSet::setNone, "([{=,:;!%^&*|?~");
const CharacterSet setOKBeforeJSRE(CharacterSet::setNone, "([{=,:;!%^&*|?~> ");
// Only allow [A-Za-z0-9.#-_:] in entities
const CharacterSet setEntity(CharacterSet::setAlphaNum, ".#-_:");
@ -1447,13 +1491,7 @@ void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int
/////////////////////////////////////
// handle the start of PHP pre-processor = Non-HTML
else if ((state != SCE_H_ASPAT) &&
!isPHPStringState(state) &&
(state != SCE_HPHP_COMMENT) &&
(state != SCE_HPHP_COMMENTLINE) &&
(ch == '<') &&
(chNext == '?') &&
!IsScriptCommentState(state)) {
else if ((ch == '<') && (chNext == '?') && IsPHPEntryState(state) && IsPHPStart(allowPHP, styler, i)) {
beforeLanguage = scriptLanguage;
scriptLanguage = segIsScriptingIndicator(styler, i + 2, i + 6, isXml ? eScriptXML : eScriptPHP);
if ((scriptLanguage != eScriptPHP) && (isStringState(state) || (state==SCE_H_COMMENT))) continue;
@ -1579,7 +1617,7 @@ void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int
}
// handle the start of ASP pre-processor = Non-HTML
else if (!isMako && !isDjango && !isCommentASPState(state) && (ch == '<') && (chNext == '%') && !isPHPStringState(state)) {
else if ((ch == '<') && (chNext == '%') && allowASP && !isCommentASPState(state) && !isPHPStringState(state)) {
styler.ColourTo(i - 1, StateToPrint);
beforePreProc = state;
if (inScriptType == eNonHtmlScript)

View File

@ -39,8 +39,9 @@ namespace {
// return 1 for [[ or ]], returns >=2 for [=[ or ]=] and so on.
// The maximum number of '=' characters allowed is 254.
int LongDelimCheck(StyleContext &sc) {
constexpr int maximumEqualCharacters = 254;
int sep = 1;
while (sc.GetRelative(sep) == '=' && sep < 0xFF)
while (sc.GetRelative(sep) == '=' && sep <= maximumEqualCharacters)
sep++;
if (sc.GetRelative(sep) == sc.ch)
return sep;
@ -115,11 +116,15 @@ public:
explicit LexerLua() :
DefaultLexer("lua", SCLEX_LUA, lexicalClasses, std::size(lexicalClasses)) {
}
LexerLua(const LexerLua &) = delete;
LexerLua(LexerLua &&) = delete;
LexerLua &operator=(const LexerLua &) = delete;
LexerLua &operator=(LexerLua &&) = delete;
~LexerLua() override = default;
void SCI_METHOD Release() noexcept override {
delete this;
}
int SCI_METHOD Version() const noexcept override {
[[nodiscard]] int SCI_METHOD Version() const noexcept override {
return lvRelease5;
}
const char *SCI_METHOD PropertyNames() noexcept override {
@ -259,6 +264,7 @@ void LexerLua::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, I
// results of identifier/keyword matching
Sci_Position idenPos = 0;
Sci_Position idenStartCharWidth = 0;
Sci_Position idenWordPos = 0;
int idenStyle = SCE_LUA_IDENTIFIER;
bool foundGoto = false;
@ -315,22 +321,22 @@ void LexerLua::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, I
if (sc.ch == ':' && sc.chPrev == ':') { // :: <label> :: forward scan
sc.Forward();
Sci_Position ln = 0;
while (IsASpaceOrTab(sc.GetRelative(ln))) // skip over spaces/tabs
while (IsASpaceOrTab(sc.GetRelativeChar(ln))) // skip over spaces/tabs
ln++;
const Sci_Position ws1 = ln;
if (setWordStart.Contains(sc.GetRelative(ln))) {
int c = 0;
if (setWordStart.Contains(sc.GetRelativeChar(ln))) {
char cLabel = 0;
std::string s;
while (setWord.Contains(c = sc.GetRelative(ln))) { // get potential label
s.push_back(static_cast<char>(c));
while (setWord.Contains(cLabel = sc.GetRelativeChar(ln))) { // get potential label
s.push_back(cLabel);
ln++;
}
const Sci_Position lbl = ln;
if (!keywords.InList(s)) {
while (IsASpaceOrTab(sc.GetRelative(ln))) // skip over spaces/tabs
while (IsASpaceOrTab(sc.GetRelativeChar(ln))) // skip over spaces/tabs
ln++;
const Sci_Position ws2 = ln - lbl;
if (sc.GetRelative(ln) == ':' && sc.GetRelative(ln + 1) == ':') {
if (sc.GetRelativeChar(ln) == ':' && sc.GetRelativeChar(ln + 1) == ':') {
// final :: found, complete valid label construct
sc.ChangeState(SCE_LUA_LABEL);
if (ws1) {
@ -359,7 +365,7 @@ void LexerLua::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, I
sc.SetState(SCE_LUA_DEFAULT);
}
} else if (sc.state == SCE_LUA_IDENTIFIER) {
idenPos--; // commit already-scanned identifier/word parts
idenPos -= idenStartCharWidth; // commit already-scanned identifier/word parts
if (idenWordPos > 0) {
idenWordPos--;
sc.ChangeState(idenStyle);
@ -449,17 +455,18 @@ void LexerLua::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, I
// set to a word style. The non-matched part is in identifier style.
std::string ident;
idenPos = 0;
idenStartCharWidth = sc.width;
idenWordPos = 0;
idenStyle = SCE_LUA_IDENTIFIER;
foundGoto = false;
int cNext = 0;
char cNext = 0;
do {
int c = 0;
char cIdent = 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);
identSeg += sc.GetRelativeChar(idenPos++);
while (setWord.Contains(cIdent = sc.GetRelativeChar(idenPos))) {
identSeg += cIdent;
idenPos++;
}
if (keywords.InList(identSeg) && (idenPosOld > 0)) {
@ -497,9 +504,9 @@ void LexerLua::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, I
}
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);
cNext = sc.GetRelativeChar(idenPos + 1);
if ((cIdent == '.' || cIdent == ':') && setWordStart.Contains(cNext)) {
ident += cIdent;
idenPos++;
} else {
cNext = 0;
@ -570,14 +577,18 @@ void LexerLua::Fold(Sci_PositionU startPos_, Sci_Position length, int initStyle,
chNext = styler.SafeGetCharAt(i + 1);
const int stylePrev = style;
style = styleNext;
if ((i + 1) < lengthDoc) {
// Only read styles that have been set, otherwise treat style as continuing
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')) {
constexpr Sci_Position maxFoldWord = 9; // "function"sv.length() + 1
std::string s;
for (Sci_Position j = 0; j < 8; j++) { // 8 is length of longest: function
for (Sci_Position j = 0; j < maxFoldWord; j++) {
if (!iswordchar(styler[i + j])) {
break;
}

View File

@ -1,65 +0,0 @@
// Scintilla source code edit control
/** @file LexerNoExceptions.cxx
** A simple lexer with no state which does not throw exceptions so can be used in an external lexer.
**/
// Copyright 1998-2010 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 <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 "LexerModule.h"
#include "LexerBase.h"
#include "LexerNoExceptions.h"
using namespace Lexilla;
Sci_Position SCI_METHOD LexerNoExceptions::PropertySet(const char *key, const char *val) {
try {
return LexerBase::PropertySet(key, val);
} catch (...) {
// Should not throw into caller as may be compiled with different compiler or options
}
return -1;
}
Sci_Position SCI_METHOD LexerNoExceptions::WordListSet(int n, const char *wl) {
try {
return LexerBase::WordListSet(n, wl);
} catch (...) {
// Should not throw into caller as may be compiled with different compiler or options
}
return -1;
}
void SCI_METHOD LexerNoExceptions::Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, Scintilla::IDocument *pAccess) {
try {
Accessor astyler(pAccess, &props);
Lexer(startPos, lengthDoc, initStyle, pAccess, astyler);
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 LexerNoExceptions::Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, Scintilla::IDocument *pAccess) {
try {
Accessor astyler(pAccess, &props);
Folder(startPos, lengthDoc, initStyle, pAccess, astyler);
astyler.Flush();
} catch (...) {
// Should not throw into caller as may be compiled with different compiler or options
pAccess->SetErrorStatus(SC_STATUS_FAILURE);
}
}

View File

@ -1,28 +0,0 @@
// Scintilla source code edit control
/** @file LexerNoExceptions.h
** A simple lexer with no state.
**/
// Copyright 1998-2010 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#ifndef LEXERNOEXCEPTIONS_H
#define LEXERNOEXCEPTIONS_H
namespace Lexilla {
// A simple lexer with no state
class LexerNoExceptions : public LexerBase {
public:
// TODO Also need to prevent exceptions in constructor and destructor
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 lengthDoc, int initStyle, Scintilla::IDocument *pAccess) override;
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, Scintilla::IDocument *) override;
virtual void Lexer(Sci_PositionU startPos, Sci_Position length, int initStyle, Scintilla::IDocument *pAccess, Accessor &styler) = 0;
virtual void Folder(Sci_PositionU startPos, Sci_Position length, int initStyle, Scintilla::IDocument *pAccess, Accessor &styler) = 0;
};
}
#endif

View File

@ -27,11 +27,11 @@ using namespace Lexilla;
LexerSimple::LexerSimple(const LexerModule *module_) :
LexerBase(module_->LexClasses(), module_->NamedStyles()),
module(module_) {
for (int wl = 0; wl < module->GetNumWordLists(); wl++) {
lexerModule(module_) {
for (int wl = 0; wl < lexerModule->GetNumWordLists(); wl++) {
if (!wordLists.empty())
wordLists += "\n";
wordLists += module->GetWordListDescription(wl);
wordLists += lexerModule->GetWordListDescription(wl);
}
}
@ -41,22 +41,22 @@ const char * SCI_METHOD LexerSimple::DescribeWordListSets() {
void SCI_METHOD LexerSimple::Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, Scintilla::IDocument *pAccess) {
Accessor astyler(pAccess, &props);
module->Lex(startPos, lengthDoc, initStyle, keyWordLists, astyler);
lexerModule->Lex(startPos, lengthDoc, initStyle, keyWordLists, astyler);
astyler.Flush();
}
void SCI_METHOD LexerSimple::Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, Scintilla::IDocument *pAccess) {
if (props.GetInt("fold")) {
Accessor astyler(pAccess, &props);
module->Fold(startPos, lengthDoc, initStyle, keyWordLists, astyler);
lexerModule->Fold(startPos, lengthDoc, initStyle, keyWordLists, astyler);
astyler.Flush();
}
}
const char * SCI_METHOD LexerSimple::GetName() {
return module->languageName;
return lexerModule->languageName;
}
int SCI_METHOD LexerSimple::GetIdentifier() {
return module->GetLanguage();
return lexerModule->GetLanguage();
}

View File

@ -12,10 +12,10 @@ namespace Lexilla {
// A simple lexer with no state
class LexerSimple : public LexerBase {
const LexerModule *module;
const LexerModule *lexerModule;
std::string wordLists;
public:
explicit LexerSimple(const LexerModule *module_);
explicit LexerSimple(const LexerModule *lexerModule_);
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;

View File

@ -120,6 +120,9 @@ public:
Sci_Position LengthCurrent() const noexcept {
return currentPos - styler.GetStartSegment();
}
char GetRelativeChar(Sci_Position n, char chDefault='\0') {
return styler.SafeGetCharAt(currentPos + n, chDefault);
}
int GetRelative(Sci_Position n, char chDefault='\0') {
const unsigned char chRelative = styler.SafeGetCharAt(currentPos + n, chDefault);
return chRelative;

View File

@ -96,7 +96,6 @@
#include "DefaultLexer.h"
#include "LexerBase.h"
#include "LexerSimple.h"
#include "LexerNoExceptions.h"
// test

View File

@ -1,7 +1,7 @@
rem Test lexers
rem build lexilla.dll and TestLexers.exe then run TestLexers.exe
cd ../src
make --jobs=4 DEBUG=1
make --jobs=%NUMBER_OF_PROCESSORS% DEBUG=1
cd ../test
make DEBUG=1
make test

View File

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

View File

@ -15,7 +15,6 @@
28BA72AC24E34D5B00272C2D /* LexAccessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BA729024E34D5A00272C2D /* LexAccessor.h */; };
28BA72AD24E34D5B00272C2D /* DefaultLexer.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BA729124E34D5A00272C2D /* DefaultLexer.h */; };
28BA72AE24E34D5B00272C2D /* SubStyles.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BA729224E34D5A00272C2D /* SubStyles.h */; };
28BA72AF24E34D5B00272C2D /* LexerNoExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BA729324E34D5A00272C2D /* LexerNoExceptions.h */; };
28BA72B024E34D5B00272C2D /* LexerModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BA729424E34D5A00272C2D /* LexerModule.h */; };
28BA72B124E34D5B00272C2D /* CharacterCategory.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 28BA729524E34D5A00272C2D /* CharacterCategory.cxx */; };
28BA72B224E34D5B00272C2D /* LexerSimple.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BA729624E34D5A00272C2D /* LexerSimple.h */; };
@ -25,7 +24,6 @@
28BA72B624E34D5B00272C2D /* SparseState.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BA729A24E34D5A00272C2D /* SparseState.h */; };
28BA72B724E34D5B00272C2D /* WordList.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BA729B24E34D5A00272C2D /* WordList.h */; };
28BA72B824E34D5B00272C2D /* DefaultLexer.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 28BA729C24E34D5A00272C2D /* DefaultLexer.cxx */; };
28BA72B924E34D5B00272C2D /* LexerNoExceptions.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 28BA729D24E34D5A00272C2D /* LexerNoExceptions.cxx */; };
28BA72BA24E34D5B00272C2D /* WordList.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 28BA729E24E34D5A00272C2D /* WordList.cxx */; };
28BA72BB24E34D5B00272C2D /* OptionSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BA729F24E34D5A00272C2D /* OptionSet.h */; };
28BA72BC24E34D5B00272C2D /* CatalogueModules.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BA72A024E34D5B00272C2D /* CatalogueModules.h */; };
@ -169,7 +167,6 @@
28BA729024E34D5A00272C2D /* LexAccessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LexAccessor.h; path = ../../lexlib/LexAccessor.h; sourceTree = "<group>"; };
28BA729124E34D5A00272C2D /* DefaultLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DefaultLexer.h; path = ../../lexlib/DefaultLexer.h; sourceTree = "<group>"; };
28BA729224E34D5A00272C2D /* SubStyles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SubStyles.h; path = ../../lexlib/SubStyles.h; sourceTree = "<group>"; };
28BA729324E34D5A00272C2D /* LexerNoExceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LexerNoExceptions.h; path = ../../lexlib/LexerNoExceptions.h; sourceTree = "<group>"; };
28BA729424E34D5A00272C2D /* LexerModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LexerModule.h; path = ../../lexlib/LexerModule.h; sourceTree = "<group>"; };
28BA729524E34D5A00272C2D /* CharacterCategory.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CharacterCategory.cxx; path = ../../lexlib/CharacterCategory.cxx; sourceTree = "<group>"; };
28BA729624E34D5A00272C2D /* LexerSimple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LexerSimple.h; path = ../../lexlib/LexerSimple.h; sourceTree = "<group>"; };
@ -179,7 +176,6 @@
28BA729A24E34D5A00272C2D /* SparseState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SparseState.h; path = ../../lexlib/SparseState.h; sourceTree = "<group>"; };
28BA729B24E34D5A00272C2D /* WordList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WordList.h; path = ../../lexlib/WordList.h; sourceTree = "<group>"; };
28BA729C24E34D5A00272C2D /* DefaultLexer.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DefaultLexer.cxx; path = ../../lexlib/DefaultLexer.cxx; sourceTree = "<group>"; };
28BA729D24E34D5A00272C2D /* LexerNoExceptions.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexerNoExceptions.cxx; path = ../../lexlib/LexerNoExceptions.cxx; sourceTree = "<group>"; };
28BA729E24E34D5A00272C2D /* WordList.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WordList.cxx; path = ../../lexlib/WordList.cxx; sourceTree = "<group>"; };
28BA729F24E34D5A00272C2D /* OptionSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptionSet.h; path = ../../lexlib/OptionSet.h; sourceTree = "<group>"; };
28BA72A024E34D5B00272C2D /* CatalogueModules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CatalogueModules.h; path = ../../lexlib/CatalogueModules.h; sourceTree = "<group>"; };
@ -500,8 +496,6 @@
28BA72A624E34D5B00272C2D /* LexerBase.h */,
28BA72A524E34D5B00272C2D /* LexerModule.cxx */,
28BA729424E34D5A00272C2D /* LexerModule.h */,
28BA729D24E34D5A00272C2D /* LexerNoExceptions.cxx */,
28BA729324E34D5A00272C2D /* LexerNoExceptions.h */,
28BA72A724E34D5B00272C2D /* LexerSimple.cxx */,
28BA729624E34D5A00272C2D /* LexerSimple.h */,
28BA729F24E34D5A00272C2D /* OptionSet.h */,
@ -528,7 +522,6 @@
28BA73AD24E34DBC00272C2D /* Lexilla.h in Headers */,
28BA72BF24E34D5B00272C2D /* PropSetSimple.h in Headers */,
28BA72B224E34D5B00272C2D /* LexerSimple.h in Headers */,
28BA72AF24E34D5B00272C2D /* LexerNoExceptions.h in Headers */,
28BA72B724E34D5B00272C2D /* WordList.h in Headers */,
28BA72C024E34D5B00272C2D /* StringCopy.h in Headers */,
28BA72AD24E34D5B00272C2D /* DefaultLexer.h in Headers */,
@ -656,7 +649,6 @@
28BA735E24E34D9700272C2D /* LexFlagship.cxx in Sources */,
28BA735B24E34D9700272C2D /* LexRuby.cxx in Sources */,
28BA735424E34D9700272C2D /* LexHollywood.cxx in Sources */,
28BA72B924E34D5B00272C2D /* LexerNoExceptions.cxx in Sources */,
28BA736D24E34D9700272C2D /* LexFortran.cxx in Sources */,
28BA738924E34D9700272C2D /* LexStata.cxx in Sources */,
28BA737524E34D9700272C2D /* LexTCMD.cxx in Sources */,
@ -866,7 +858,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5.3.2;
CURRENT_PROJECT_VERSION = 5.3.3;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 4F446KW87E;
DYLIB_COMPATIBILITY_VERSION = 1;
@ -894,7 +886,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5.3.2;
CURRENT_PROJECT_VERSION = 5.3.3;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 4F446KW87E;
DYLIB_COMPATIBILITY_VERSION = 1;

View File

@ -4,8 +4,8 @@
#include <windows.h>
#define VERSION_LEXILLA "5.3.2"
#define VERSION_WORDS 5, 3, 2, 0
#define VERSION_LEXILLA "5.3.3"
#define VERSION_WORDS 5, 3, 3, 0
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_WORDS

View File

@ -68,19 +68,6 @@ $(DIR_O)/LexerModule.o: \
../lexlib/LexerModule.h \
../lexlib/LexerBase.h \
../lexlib/LexerSimple.h
$(DIR_O)/LexerNoExceptions.o: \
../lexlib/LexerNoExceptions.cxx \
../../scintilla/include/ILexer.h \
../../scintilla/include/Sci_Position.h \
../../scintilla/include/Scintilla.h \
../include/SciLexer.h \
../lexlib/PropSetSimple.h \
../lexlib/WordList.h \
../lexlib/LexAccessor.h \
../lexlib/Accessor.h \
../lexlib/LexerModule.h \
../lexlib/LexerBase.h \
../lexlib/LexerNoExceptions.h
$(DIR_O)/LexerSimple.o: \
../lexlib/LexerSimple.cxx \
../../scintilla/include/ILexer.h \

View File

@ -7,6 +7,11 @@
# For debug versions define DEBUG on the command line:
# nmake DEBUG=1 -f lexilla.mak
# To build with GCC or Clang, run makefile
#
# Command line options
# DEBUG Debug build.
# QUIET Avoid most compiler invocation output and copyright info.
# SUPPORT_XP Build for Windows XP.
.SUFFIXES: .cxx
@ -21,7 +26,7 @@ LD=link
!IFDEF SUPPORT_XP
ADD_DEFINE=-D_USING_V110_SDK71_
# Different subsystems for 32-bit and 64-bit Windows XP so detect based on Platform
# environment vairable set by vcvars*.bat to be either x86 or x64
# environment variable set by vcvars*.bat to be either x86 or x64
!IF "$(PLATFORM)" == "x64"
SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.02
!ELSE
@ -224,7 +229,7 @@ LEXILLA_OBJS=\
$(LEXLIB_OBJS) \
$(LEX_OBJS)
$(LEXILLA): $(LEXILLA_OBJS) LexillaVersion.res
$(LEXILLA): $(LEXILLA_OBJS) $(DIR_O)\LexillaVersion.res
$(LD) $(LDFLAGS) -DEF:Lexilla.def -DLL -OUT:$@ $** $(LIBS)
$(LIBLEXILLA): $(LEXILLA_OBJS)
@ -239,7 +244,7 @@ $(LIBLEXILLA): $(LEXILLA_OBJS)
{.}.cxx{$(DIR_O)}.obj::
$(CXX) $(CXXFLAGS) -c $(NAME)$(DIR_O)\ $<
.rc.res:
.rc{$(DIR_O)}.res:
$(RC) -fo$@ $**
# Dependencies

View File

@ -68,19 +68,6 @@ $(DIR_O)/LexerModule.obj: \
../lexlib/LexerModule.h \
../lexlib/LexerBase.h \
../lexlib/LexerSimple.h
$(DIR_O)/LexerNoExceptions.obj: \
../lexlib/LexerNoExceptions.cxx \
../../scintilla/include/ILexer.h \
../../scintilla/include/Sci_Position.h \
../../scintilla/include/Scintilla.h \
../include/SciLexer.h \
../lexlib/PropSetSimple.h \
../lexlib/WordList.h \
../lexlib/LexAccessor.h \
../lexlib/Accessor.h \
../lexlib/LexerModule.h \
../lexlib/LexerBase.h \
../lexlib/LexerNoExceptions.h
$(DIR_O)/LexerSimple.obj: \
../lexlib/LexerSimple.cxx \
../../scintilla/include/ILexer.h \

View File

@ -1,3 +1,5 @@
#!/usr/bin/env node
// A demonstration program
#include <stdio.h>
#if 0 /* */
@ -70,6 +72,9 @@ int main() {
// JavaScript regular expression (14) tests
let a = /a/;
let b = /[a-z]+/gi;
/a|b/i.test("baby");
// arrow function
() => /a|b/i.test("baby");
// Escape sequence (27) tests
printf("\'\"\?\\\a\b\f\n\r\t\v \P");

View File

@ -1,3 +1,5 @@
0 400 400 #!/usr/bin/env node
1 400 400
0 400 400 // A demonstration program
0 400 400 #include <stdio.h>
2 400 401 + #if 0 /* */
@ -70,6 +72,9 @@
0 401 401 | // JavaScript regular expression (14) tests
0 401 401 | let a = /a/;
0 401 401 | let b = /[a-z]+/gi;
0 401 401 | /a|b/i.test("baby");
0 401 401 | // arrow function
0 401 401 | () => /a|b/i.test("baby");
1 401 401 |
0 401 401 | // Escape sequence (27) tests
0 401 401 | printf("\'\"\?\\\a\b\f\n\r\t\v \P");

View File

@ -1,3 +1,5 @@
{2}#!/usr/bin/env node
{0}
{2}// A demonstration program
{9}#include <stdio.h>
#if 0 {23}/* */{9}
@ -70,6 +72,9 @@
{2}// JavaScript regular expression (14) tests
{0} {5}let{0} {11}a{0} {10}={0} {14}/a/{10};{0}
{5}let{0} {11}b{0} {10}={0} {14}/[a-z]+/gi{10};{0}
{14}/a|b/i{10}.{11}test{10}({6}"baby"{10});{0}
{2}// arrow function
{0} {10}(){0} {10}=>{0} {14}/a|b/i{10}.{11}test{10}({6}"baby"{10});{0}
{2}// Escape sequence (27) tests
{0} {11}printf{10}({6}"{27}\'\"\?\\\a\b\f\n\r\t\v{6} {27}\P{6}"{10});{0}

View File

@ -0,0 +1,5 @@
<script>
/a|b/i.test("baby");
// arrow function
() => /a|b/i.test("baby");
</script>

View File

@ -0,0 +1,6 @@
2 400 0 + <script>
0 401 0 | /a|b/i.test("baby");
0 401 0 | // arrow function
0 401 0 | () => /a|b/i.test("baby");
0 401 0 | </script>
0 400 0

View File

@ -0,0 +1,5 @@
{1}<script>{40}
{52}/a|b/i{46}.test{50}({48}"baby"{50});{41}
{43}// arrow function{41}
{50}(){41} {50}=>{41} {52}/a|b/i{46}.test{50}({48}"baby"{50});{41}
{1}</script>{0}

View File

@ -0,0 +1,22 @@
<!-- Check PHP start tags for issue 252 -->
<!-- Full PHP tag: enabled -->
<?php
echo __FILE__.__LINE__;
?>
<!-- Short echo tag: enabled -->
<?= 'echo' ?>
<!-- Short tag: disabled -->
<?
echo 'short'
?>
<!-- ASP language selection: disabled -->
<%@language=JScript%>
<!-- ASP tag: disabled -->
<%
Response.Write('short')
%>

View File

@ -0,0 +1,23 @@
0 400 0 <!-- Check PHP start tags for issue 252 -->
1 400 0
0 400 0 <!-- Full PHP tag: enabled -->
2 400 0 + <?php
0 401 0 | echo __FILE__.__LINE__;
0 401 0 | ?>
1 400 0
0 400 0 <!-- Short echo tag: enabled -->
0 400 0 <?= 'echo' ?>
1 400 0
0 400 0 <!-- Short tag: disabled -->
0 400 0 <?
0 400 0 echo 'short'
2 400 0 + ?>
1 401 0 |
0 401 0 | <!-- ASP language selection: disabled -->
2 401 0 + <%@language=JScript%>
1 402 0 |
0 402 0 | <!-- ASP tag: disabled -->
0 402 0 | <%
0 402 0 | Response.Write('short')
2 402 0 + %>
0 403 0 |

View File

@ -0,0 +1,22 @@
{9}<!-- Check PHP start tags for issue 252 -->{0}
{9}<!-- Full PHP tag: enabled -->{0}
{18}<?php{118}
{121}echo{118} {121}__FILE__{127}.{121}__LINE__{127};{118}
{18}?>{0}
{9}<!-- Short echo tag: enabled -->{0}
{18}<?{127}={118} {120}'echo'{118} {18}?>{0}
{9}<!-- Short tag: disabled -->{0}
{2}<?
echo 'short'
?>{0}
{9}<!-- ASP language selection: disabled -->{0}
{2}<%@language=JScript%>{0}
{9}<!-- ASP tag: disabled -->{0}
{2}<%
Response.Write('short')
%>{0}

View File

@ -1,6 +1,6 @@
lexer.*=hypertext
# Tags and attributes
keywords.*=b br body content encoding head href html img language li link meta \
keywords.*=b br body content div encoding head href html img language li link meta \
name p rel runat script src strong title type ul version xml xmlns
# JavaScript
keywords2.*=function var
@ -42,3 +42,7 @@ fold.hypertext.comment=1
match mako.html
lexer.html.mako=1
match Issue252Tag.php
lexer.html.allow.php=1
lexer.html.allow.asp=0

View File

@ -6,6 +6,8 @@ echo "<!-- -->\n";
/* ?> */
?>
<strong>for</strong><b>if</b>
<?= 'short echo tag' ?>
<? echo 'short tag' ?>
<script>
alert("<?php echo "PHP" . ' Code'; ?>");
alert('<?= 'PHP' . "Code"; ?>');

View File

@ -6,6 +6,8 @@
0 402 0 | /* ?> */
0 402 0 | ?>
0 401 0 | <strong>for</strong><b>if</b>
0 401 0 | <?= 'short echo tag' ?>
0 401 0 | <? echo 'short tag' ?>
2 401 0 + <script>
0 402 0 | alert("<?php echo "PHP" . ' Code'; ?>");
0 402 0 | alert('<?= 'PHP' . "Code"; ?>');

View File

@ -6,6 +6,8 @@
{124}/* ?> */{118}
{18}?>{0}
{1}<strong>{0}for{1}</strong><b>{0}if{1}</b>{0}
{18}<?{127}={118} {120}'short echo tag'{118} {18}?>{0}
{18}<?{118} {121}echo{118} {120}'short tag'{118} {18}?>{0}
{1}<script>{40}
{41} {46}alert{50}({48}"{18}<?php{118} {121}echo{118} {119}"PHP"{118} {127}.{118} {120}' Code'{127};{118} {18}?>{48}"{50});{41}
{46}alert{50}({49}'{18}<?{127}={118} {120}'PHP'{118} {127}.{118} {119}"Code"{127};{118} {18}?>{49}'{50});{41}

View File

@ -0,0 +1,12 @@
-- Tests behaviour with non-ASCII identifiers joined with '.' or ':'
:("提示"):("输出"):("提示&输出"):("Log")
:(0,:() + :()):(_X.x,_Y:()):()
:(10,"グリップ"):("グリップ")
:("레이블")
δέλτα:ζήτα("δέλτα")
źdźbło.krnąbrność(0)
🍣😂:💮("😂")
string:rep("ddf"):gsub("ddf","ffd")

View File

@ -0,0 +1,13 @@
0 400 0 -- Tests behaviour with non-ASCII identifiers joined with '.' or ':'
0 400 0 输出栏选择夹:加入子夹("提示"):加入子夹("输出"):加入子夹("提示&输出"):加入子夹("Log")
0 400 0 支持库管理器:置坐标(0,工具栏:取高度() + 资源栏选择夹:取高度()):置宽高(分隔条_X.x,分隔条_Y:取坐标()):显示()
1 400 0
0 400 0 選択グリップ:に参加(10,"グリップ"):に参加("グリップ")
1 400 0
0 400 0 클립선택:가입("레이블")
0 400 0 δέλτα:ζήτα("δέλτα")
0 400 0 źdźbło.krnąbrność(0)
0 400 0 🍣😂:💮("😂")
1 400 0
0 400 0 string:rep("ddf"):gsub("ddf","ffd")
0 400 0

View File

@ -0,0 +1,12 @@
{2}-- Tests behaviour with non-ASCII identifiers joined with '.' or ':'
{11}输出栏选择夹:加入子夹{10}({6}"提示"{10}):{11}加入子夹{10}({6}"输出"{10}):{11}加入子夹{10}({6}"提示&输出"{10}):{11}加入子夹{10}({6}"Log"{10}){0}
{11}支持库管理器:置坐标{10}({4}0{10},{11}工具栏:取高度{10}(){0} {10}+{0} {11}资源栏选择夹:取高度{10}()):{11}置宽高{10}({11}分隔条_X.x{10},{11}分隔条_Y:取坐标{10}()):{11}显示{10}(){0}
{11}選択グリップ:に参加{10}({4}10{10},{6}"グリップ"{10}):{11}に参加{10}({6}"グリップ"{10}){0}
{11}클립선택:가입{10}({6}"레이블"{10}){0}
{11}δέλτα:ζήτα{10}({6}"δέλτα"{10}){0}
{11}źdźbło.krnąbrność{10}({4}0{10}){0}
{11}🍣😂:💮{10}({6}"😂"{10}){0}
{11}string:rep{10}({6}"ddf"{10}):{11}gsub{10}({6}"ddf"{10},{6}"ffd"{10}){0}

View File

@ -1,5 +1,5 @@
# Build the lexers test with Microsoft Visual C++ using nmake
# Tested with Visual C++ 2019
# Tested with Visual C++ 2022
DEL = del /q
EXE = TestLexers.exe
@ -35,9 +35,6 @@ $(EXE): $(OBJS) $(LIBS)
.cxx.obj::
$(CXX) $(CXXFLAGS) -c $<
{..\access}.cxx.obj::
$(CXX) $(CXXFLAGS) -c $(NAME) $<
.cxx.obj::
$(CXX) $(CXXFLAGS) -c $<
TestLexers.obj: $*.cxx TestDocument.h

View File

@ -74,5 +74,5 @@ clean:
%.o: %.cxx
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
$(EXE): $(TESTOBJ) $(TESTEDOBJ) unitTest.o
$(EXE): unitTest.o $(TESTOBJ) $(TESTEDOBJ)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LINKFLAGS) $^ -o $@

View File

@ -1,16 +1,16 @@
# Build all the unit tests with Microsoft Visual C++ using nmake
# Tested with Visual C++ 2019
# Tested with Visual C++ 2022
DEL = del /q
EXE = unitTest.exe
INCLUDEDIRS = /I../../include /I../../lexlib /I../../../scintilla/include
CXXFLAGS = /EHsc /std:c++17 /D_HAS_AUTO_PTR_ETC=1 /wd 4805 $(INCLUDEDIRS)
CXXFLAGS = /MP /EHsc /std:c++17 /D_HAS_AUTO_PTR_ETC=1 /wd 4805 $(INCLUDEDIRS)
# Files in this directory containing tests
TESTSRC=test*.cxx
# Files being tested from scintilla/src directory
# Files being tested from lexilla/lexlib directory
TESTEDSRC=\
../../lexlib/Accessor.cxx \
../../lexlib/CharacterSet.cxx \
@ -31,5 +31,5 @@ test: $(TESTS)
clean:
$(DEL) $(TESTS) *.o *.obj *.exe
$(EXE): $(TESTSRC) $(TESTEDSRC) $(@B).obj
$(EXE): $(TESTSRC) $(TESTEDSRC) $(@B).cxx
$(CXX) $(CXXFLAGS) /Fe$@ $**

View File

@ -34,7 +34,7 @@ LexerModule lmSimpleExample(123456, ColouriseDocument, "simpleexample");
}
TEST_CASE("LexerNoExceptions") {
TEST_CASE("LexerSimple") {
SECTION("Identifier") {
LexerSimple lexSimple(&lmSimpleExample);

View File

@ -1 +1 @@
532
533

View File

@ -1095,6 +1095,14 @@ int ScintillaCall::AutoCGetMaxHeight() {
return static_cast<int>(Call(Message::AutoCGetMaxHeight));
}
void ScintillaCall::AutoCSetStyle(int style) {
Call(Message::AutoCSetStyle, style);
}
int ScintillaCall::AutoCGetStyle() {
return static_cast<int>(Call(Message::AutoCGetStyle));
}
void ScintillaCall::SetIndent(int indentSize) {
Call(Message::SetIndent, indentSize);
}
@ -2711,6 +2719,10 @@ void ScintillaCall::CopyAllowLine() {
Call(Message::CopyAllowLine);
}
void ScintillaCall::CutAllowLine() {
Call(Message::CutAllowLine);
}
void *ScintillaCall::CharacterPointer() {
return reinterpret_cast<void *>(Call(Message::GetCharacterPointer));
}

View File

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

View File

@ -582,7 +582,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 5.5.0;
CURRENT_PROJECT_VERSION = 5.5.1;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -647,7 +647,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 5.5.0;
CURRENT_PROJECT_VERSION = 5.5.1;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
@ -680,7 +680,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5.5.0;
CURRENT_PROJECT_VERSION = 5.5.1;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
@ -715,7 +715,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5.5.0;
CURRENT_PROJECT_VERSION = 5.5.1;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";

View File

@ -27,12 +27,13 @@ constStatement:scintilla/src/Document.cxx
// ILexer5* is not pointing at logically const
constParameterPointer:scintilla/src/Document.cxx
// Doesn't seem to understand that values change in loops
knownConditionTrueFalse:scintilla/src/Document.cxx
// Some non-explicit constructors are used for conversions or are private to lexers
noExplicitConstructor
// RangesCopy is deliberately returning a copy.
// The copy is always mutated so returning a refererence just enables lifetime problems.
returnByReference:scintilla/src/Selection.h
// MarginView access to all bits is safe and is better defined in later versions of C++
shiftTooManyBitsSigned:scintilla/src/MarginView.cxx

View File

@ -10,6 +10,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Scintilla Documentation</title>
<link rel="canonical" href="https://scintilla.org/ScintillaDoc.html" />
<style type="text/css">
<!--
@ -666,15 +667,17 @@
<p><b id="SCI_RELEASEALLEXTENDEDSTYLES">SCI_RELEASEALLEXTENDEDSTYLES</b><br />
<b id="SCI_ALLOCATEEXTENDEDSTYLES">SCI_ALLOCATEEXTENDEDSTYLES(int numberStyles) &rarr; int</b><br />
Extended styles are used for features like textual margins and annotations as well as internally by Scintilla.
Extended styles are used for features like textual margins and annotations and autocompletion lists as well as
internally by Scintilla.
They are outside the range 0..255 used for the styles bytes associated with document bytes.
These functions manage the use of extended styles to ensures that components cooperate in defining styles.
<code>SCI_RELEASEALLEXTENDEDSTYLES</code> releases any extended styles allocated by the container.
<code>SCI_ALLOCATEEXTENDEDSTYLES</code> allocates a range of style numbers after the byte style values and returns
the number of the first allocated style.
Ranges for margin and annotation styles should be allocated before calling
Ranges for margin, annotation, and autocompletion list styles should be allocated before calling
<a class="seealso" href="#SCI_MARGINSETSTYLEOFFSET">SCI_MARGINSETSTYLEOFFSET</a> or
<a class="seealso" href="#SCI_ANNOTATIONSETSTYLEOFFSET">SCI_ANNOTATIONSETSTYLEOFFSET</a>.</p>
<a class="seealso" href="#SCI_ANNOTATIONSETSTYLEOFFSET">SCI_ANNOTATIONSETSTYLEOFFSET</a> or
<a class="seealso" href="#SCI_AUTOCSETSTYLE">SCI_AUTOCSETSTYLE</a>.</p>
<p><b id="Sci_TextRange">Sci_TextRange</b> and <b id="Sci_CharacterRange">Sci_CharacterRange</b><br />
These structures are defined to be exactly the same shape as the Win32 <code>TEXTRANGE</code>
@ -1852,6 +1855,7 @@ struct Sci_TextToFindFull {
<a class="message" href="#SCI_COPYRANGE">SCI_COPYRANGE(position start, position end)</a><br />
<a class="message" href="#SCI_COPYTEXT">SCI_COPYTEXT(position length, const char *text)</a><br />
<a class="message" href="#SCI_COPYALLOWLINE">SCI_COPYALLOWLINE</a><br />
<a class="message" href="#SCI_CUTALLOWLINE">SCI_CUTALLOWLINE</a><br />
<a class="message" href="#SCI_SETPASTECONVERTENDINGS">SCI_SETPASTECONVERTENDINGS(bool convert)</a><br />
<a class="message" href="#SCI_GETPASTECONVERTENDINGS">SCI_GETPASTECONVERTENDINGS &rarr; bool</a><br />
<a class="message" href="#SCI_REPLACERECTANGULAR">SCI_REPLACERECTANGULAR(position length, const char *text)</a><br />
@ -1863,6 +1867,7 @@ struct Sci_TextToFindFull {
<b id="SCI_CLEAR">SCI_CLEAR</b><br />
<b id="SCI_CANPASTE">SCI_CANPASTE &rarr; bool</b><br />
<b id="SCI_COPYALLOWLINE">SCI_COPYALLOWLINE</b><br />
<b id="SCI_CUTALLOWLINE">SCI_CUTALLOWLINE</b><br />
These commands perform the standard tasks of cutting and copying data to the clipboard,
pasting from the clipboard into the document, and clearing the document.
<code>SCI_CANPASTE</code> returns non-zero if the document isn't read-only and if the selection
@ -1880,6 +1885,11 @@ struct Sci_TextToFindFull {
<p><code>SCI_COPYALLOWLINE</code> works the same as SCI_COPY except that if the
selection is empty then the current line is copied. On Windows, an extra "MSDEVLineSelect" marker
is added to the clipboard which is then used in <code>SCI_PASTE</code> to paste
the whole line before the current line.</p>
<p><code>SCI_CUTALLOWLINE</code> works the same as SCI_CUT except that if the
selection is empty then the current line is cut. On Windows, an extra "MSDEVLineSelect" marker
is added to the clipboard which is then used in <code>SCI_PASTE</code> to paste
the whole line before the current line.</p>
<b id="SCI_COPYRANGE">SCI_COPYRANGE(position start, position end)</b><br />
@ -2225,6 +2235,9 @@ struct Sci_TextToFindFull {
</tbody>
</table>
<p>The bits used for change history markers are specified by <code>SC_MASK_HISTORY</code>, which is commonly
used as an argument to <code>SCI_SETMARGINMASKN</code> when defining a margin to be used for change history.</p>
<p>Indicators:</p>
<table class="standard" summary="Change history indicators">
@ -4460,8 +4473,10 @@ struct Sci_TextToFindFull {
The mask is a 32-bit value. Each bit corresponds to one of 32 logical symbols that can be
displayed in a margin that is enabled for symbols. There is a useful constant,
<code>SC_MASK_FOLDERS</code> (0xFE000000 or -33554432), that is a mask for the 7 logical
symbols used to denote folding. You can assign a wide range of symbols and colours to each of
the 32 logical symbols, see <a href="#Markers">Markers</a> for more information. If <code>(mask
symbols used to denote folding, and another, <code>SC_MASK_HISTORY</code> (0x01E00000 or
31457280), that is a mask for the 4 logical symbols used to denote change history. You can
assign a wide range of symbols and colours to each of the 32 logical symbols, see
<a href="#Markers">Markers</a> for more information. If <code>(mask
&amp; SC_MASK_FOLDERS)==0</code>, the margin background colour is controlled by style 33 (<a
class="message" href="#StyleDefinition"><code>STYLE_LINENUMBER</code></a>).</p>
@ -6494,6 +6509,16 @@ struct Sci_TextToFindFull {
the available width are indicated by the presence of ellipsis.
</p>
<p>
<b id="SCI_AUTOCSETSTYLE">SCI_AUTOCSETSTYLE</b><br />
<b id="SCI_AUTOCGETSTYLE">SCI_AUTOCGETSTYLE &rarr; int</b><br />
Get or set the style used by autocompletion lists to determine the font facename, size and character set used to display characters. Defaults
to <code><a class="message" href="#StyleDefinition">STYLE_DEFAULT</a></code>. Always call
<a class="seealso" href="#SCI_ALLOCATEEXTENDEDSTYLES">SCI_ALLOCATEEXTENDEDSTYLES(1)</a> before <code>SCI_AUTOCSETSTYLE</code> and use the
result as the argument to <code>SCI_AUTOCSETSTYLE</code> and <code>SCI_STYLESETFONT</code> and others.
</p>
<p>
<b id="SC_ELEMENT_LIST">SC_ELEMENT_LIST : colouralpha</b><br />
<b id="SC_ELEMENT_LIST_BACK">SC_ELEMENT_LIST_BACK : colouralpha</b><br />
@ -8246,7 +8271,7 @@ sptr_t CallScintilla(unsigned int iMessage, uptr_t wParam, sptr_t lParam){
<p>Scintilla incorporates a "zoom factor" that lets you make all the text in the document
larger or smaller in steps of one point. The displayed point size never goes below 2, whatever
zoom factor you set. You can set zoom factors in the range -10 to +20 points.</p>
zoom factor you set. You can set zoom factors in the range -10 to +60 points.</p>
<code><a class="message" href="#SCI_ZOOMIN">SCI_ZOOMIN</a><br />
<a class="message" href="#SCI_ZOOMOUT">SCI_ZOOMOUT</a><br />
<a class="message" href="#SCI_SETZOOM">SCI_SETZOOM(int zoomInPoints)</a><br />
@ -8256,13 +8281,13 @@ sptr_t CallScintilla(unsigned int iMessage, uptr_t wParam, sptr_t lParam){
<p><b id="SCI_ZOOMIN">SCI_ZOOMIN</b><br />
<b id="SCI_ZOOMOUT">SCI_ZOOMOUT</b><br />
<code>SCI_ZOOMIN</code> increases the zoom factor by one point if the current zoom factor is
less than 20 points. <code>SCI_ZOOMOUT</code> decreases the zoom factor by one point if the
less than 60 points. <code>SCI_ZOOMOUT</code> decreases the zoom factor by one point if the
current zoom factor is greater than -10 points.</p>
<p><b id="SCI_SETZOOM">SCI_SETZOOM(int zoomInPoints)</b><br />
<b id="SCI_GETZOOM">SCI_GETZOOM &rarr; int</b><br />
These messages let you set and get the zoom factor directly. There is no limit set on the
factors you can set, so limiting yourself to -10 to +20 to match the incremental zoom functions
factors you can set, so limiting yourself to -10 to +60 to match the incremental zoom functions
is a good idea.</p>
<h2 id="LongLines">Long lines</h2>

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/scintilla550.zip">
<font size="4"> <a href="https://www.scintilla.org/scintilla551.zip">
Windows</a>&nbsp;&nbsp;
<a href="https://www.scintilla.org/scintilla550.tgz">
<a href="https://www.scintilla.org/scintilla551.tgz">
GTK/Linux</a>&nbsp;&nbsp;
</font>
</td>
@ -42,7 +42,7 @@
containing very few restrictions.
</p>
<h3>
Release 5.5.0
Release 5.5.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/scintilla550.zip">zip format</a> (1.8M) commonly used on Windows</li>
<li><a href="https://www.scintilla.org/scintilla550.tgz">tgz format</a> (1.7M) commonly used on Linux and compatible operating systems</li>
<li><a href="https://www.scintilla.org/scintilla551.zip">zip format</a> (1.8M) commonly used on Windows</li>
<li><a href="https://www.scintilla.org/scintilla551.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

@ -10,6 +10,7 @@
<title>
Scintilla
</title>
<link rel="canonical" href="https://scintilla.org/ScintillaHistory.html" />
<style type="text/css">
table {
border-collapse: collapse;
@ -580,9 +581,34 @@
<td>Chengzhi Li</td>
<td>Gary James</td>
<td>Tsuyoshi Miyake</td>
<td>Martijn Laan</td>
</tr>
</table>
<h2>Releases</h2>
<h3>
<a href="https://www.scintilla.org/scintilla551.zip">Release 5.5.1</a>
</h3>
<ul>
<li>
Released 22 July 2024.
</li>
<li>
SCI_CUTALLOWLINE added which is similar to SCI_COPYALLOWLINE but also deletes the copied text.
<a href="https://sourceforge.net/p/scintilla/feature-requests/1518/">Feature #1518</a>.
</li>
<li>
Can set font used for autocompletion lists with SCI_AUTOCSETSTYLE.
<a href="https://sourceforge.net/p/scintilla/feature-requests/1523/">Feature #1523</a>.
</li>
<li>
Increase maximum zoom set interactively to +60 points.
<a href="https://sourceforge.net/p/scintilla/feature-requests/1517/">Feature #1517</a>.
</li>
<li>
Fix flickering cursor after some mouse action sequences.
<a href="https://sourceforge.net/p/scintilla/bugs/2443/">Bug #2443</a>.
</li>
</ul>
<h3>
<a href="https://www.scintilla.org/scintilla550.zip">Release 5.5.0</a>
</h3>

View File

@ -10,6 +10,7 @@
<title>
Scintilla and SciTE Related Sites
</title>
<link rel="canonical" href="https://scintilla.org/ScintillaRelated.html" />
</head>
<body bgcolor="#FFFFFF" text="#000000">
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0">

View File

@ -24,6 +24,7 @@
<title>
Scintilla and SciTE To Do
</title>
<link rel="canonical" href="https://scintilla.org/ScintillaToDo.html" />
</head>
<body bgcolor="#FFFFFF" text="#000000">
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0">

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="20240423" />
<meta name="Date.Modified" content="20240722" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
.logo {
@ -51,6 +51,7 @@
<title>
Scintilla and SciTE
</title>
<link rel="canonical" href="https://scintilla.org/" />
</head>
<body bgcolor="#FFFFFF" text="#000000">
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0">
@ -60,8 +61,8 @@
GTK, and macOS</font>
</td>
<td width="40%" align="right">
<font color="#FFCC99" size="3"> Release version 5.5.0<br />
Site last modified April 23 2024</font>
<font color="#FFCC99" size="3"> Release version 5.5.1<br />
Site last modified July 22 2024</font>
</td>
<td width="20%">
&nbsp;
@ -76,11 +77,11 @@
</tr>
</table>
<ul id="versionlist">
<li>Version 5.5.0 fixes adds elements for inactive additional selections.</li>
<li>Version 5.5.1 adds SCI_CUTALLOWLINE and fixes a Win32 bug that caused the cursor to flicker.</li>
<li>Version 5.5.0 adds elements for inactive additional selections.</li>
<li>Version 5.4.3 fixes a redo bug.</li>
<li>Version 5.4.2 can save and restore undo history.</li>
<li>Version 5.4.1 adds IDocumentEditable interface to allow efficient interaction with document objects.</li>
<li>Version 5.4.0 fixes crashes on macOS 12 and older when built with Xcode 15.0.</li>
</ul>
<ul id="menu">
<li id="remote1"><a href="https://www.scintilla.org/SciTEImage.html">Screenshot</a></li>

View File

@ -1353,6 +1353,7 @@ void Window::SetCursor(Cursor curs) {
if (WindowFromWidget(PWidget(wid)))
gdk_window_set_cursor(WindowFromWidget(PWidget(wid)), gdkCurs);
if (gdkCurs)
UnRefCursor(gdkCurs);
}

View File

@ -293,7 +293,7 @@ private:
class GObjectWatcher {
GObject *weakRef;
void WeakNotifyThis(GObject *obj G_GNUC_UNUSED) {
void WeakNotifyThis([[maybe_unused]] GObject *obj) {
PLATFORM_ASSERT(obj == weakRef);
Destroyed();

View File

@ -166,6 +166,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP
#define SC_MARKNUM_FOLDERSUB 29
#define SC_MARKNUM_FOLDER 30
#define SC_MARKNUM_FOLDEROPEN 31
#define SC_MASK_HISTORY 0x01E00000
#define SC_MASK_FOLDERS 0xFE000000
#define SCI_MARKERDEFINE 2040
#define SCI_MARKERSETFORE 2041
@ -461,6 +462,8 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP
#define SCI_AUTOCGETMAXWIDTH 2209
#define SCI_AUTOCSETMAXHEIGHT 2210
#define SCI_AUTOCGETMAXHEIGHT 2211
#define SCI_AUTOCSETSTYLE 2109
#define SCI_AUTOCGETSTYLE 2120
#define SCI_SETINDENT 2122
#define SCI_GETINDENT 2123
#define SCI_SETUSETABS 2124
@ -977,6 +980,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP
#define SCI_SETLAYOUTTHREADS 2775
#define SCI_GETLAYOUTTHREADS 2776
#define SCI_COPYALLOWLINE 2519
#define SCI_CUTALLOWLINE 2810
#define SCI_GETCHARACTERPOINTER 2520
#define SCI_GETRANGEPOINTER 2643
#define SCI_GETGAPPOSITION 2644

View File

@ -410,6 +410,8 @@ ali SC_MARKNUM_FOLDERTAIL=FOLDER_TAIL
ali SC_MARKNUM_FOLDERSUB=FOLDER_SUB
ali SC_MARKNUM_FOLDEROPEN=FOLDER_OPEN
val SC_MASK_HISTORY=0x01E00000
# SC_MASK_FOLDERS doesn't go in an enumeration as larger than max 32-bit positive integer
val SC_MASK_FOLDERS=0xFE000000
@ -1146,6 +1148,12 @@ set void AutoCSetMaxHeight=2210(int rowCount,)
# Set the maximum height, in rows, of auto-completion and user lists.
get int AutoCGetMaxHeight=2211(,)
# Set the style number used for auto-completion and user lists fonts.
set void AutoCSetStyle=2109(int style,)
# Get the style number used for auto-completion and user lists fonts.
get int AutoCGetStyle=2120(,)
# Set the number of spaces used for one level of indentation.
set void SetIndent=2122(int indentSize,)
@ -2657,6 +2665,9 @@ get int GetLayoutThreads=2776(,)
# Copy the selection, if selection empty copy the line with the caret
fun void CopyAllowLine=2519(,)
# Cut the selection, if selection empty cut the line with the caret
fun void CutAllowLine=2810(,)
# Compact the document buffer and return a read-only pointer to the
# characters in the document.
get pointer GetCharacterPointer=2520(,)

View File

@ -319,6 +319,8 @@ public:
int AutoCGetMaxWidth();
void AutoCSetMaxHeight(int rowCount);
int AutoCGetMaxHeight();
void AutoCSetStyle(int style);
int AutoCGetStyle();
void SetIndent(int indentSize);
int Indent();
void SetUseTabs(bool useTabs);
@ -723,6 +725,7 @@ public:
void SetLayoutThreads(int threads);
int LayoutThreads();
void CopyAllowLine();
void CutAllowLine();
void *CharacterPointer();
void *RangePointer(Position start, Position lengthRange);
Position GapPosition();

View File

@ -244,6 +244,8 @@ enum class Message {
AutoCGetMaxWidth = 2209,
AutoCSetMaxHeight = 2210,
AutoCGetMaxHeight = 2211,
AutoCSetStyle = 2109,
AutoCGetStyle = 2120,
SetIndent = 2122,
GetIndent = 2123,
SetUseTabs = 2124,
@ -637,6 +639,7 @@ enum class Message {
SetLayoutThreads = 2775,
GetLayoutThreads = 2776,
CopyAllowLine = 2519,
CutAllowLine = 2810,
GetCharacterPointer = 2520,
GetRangePointer = 2643,
GetGapPosition = 2644,

View File

@ -691,6 +691,7 @@ using sptr_t = intptr_t;
constexpr Position InvalidPosition = -1;
constexpr int CpUtf8 = 65001;
constexpr int MarkerMax = 31;
constexpr int MaskHistory = 0x01E00000;
constexpr int MaskFolders = 0xFE000000;
constexpr int MaxMargin = 4;
constexpr int FontSizeMultiplier = 100;

View File

@ -13,7 +13,7 @@ TEMPLATE = lib
CONFIG += lib_bundle
CONFIG += c++1z
VERSION = 5.5.0
VERSION = 5.5.1
SOURCES += \
ScintillaEdit.cpp \

View File

@ -83,7 +83,7 @@ private:
public:
SurfaceImpl();
SurfaceImpl(int width, int height, SurfaceMode mode_);
virtual ~SurfaceImpl();
virtual ~SurfaceImpl() override;
void Init(WindowID wid) override;
void Init(SurfaceID sid, WindowID wid) override;

View File

@ -13,7 +13,7 @@ TEMPLATE = lib
CONFIG += lib_bundle
CONFIG += c++1z
VERSION = 5.5.0
VERSION = 5.5.1
SOURCES += \
PlatQt.cpp \

View File

@ -52,6 +52,11 @@
using namespace Scintilla;
using namespace Scintilla::Internal;
#if defined(__GNUC__) && !defined(__clang__)
// False warnings from g++ 14.1 for UTF-8 accumulation code where UTF8MaxBytes allocated.
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
LexInterface::LexInterface(Document *pdoc_) noexcept : pdoc(pdoc_), performingStyle(false) {
}
@ -1711,20 +1716,29 @@ void Document::Indent(bool forwards, Sci::Line lineBottom, Sci::Line lineTop) {
}
}
namespace {
constexpr std::string_view EOLForMode(EndOfLine eolMode) noexcept {
switch (eolMode) {
case EndOfLine::CrLf:
return "\r\n";
case EndOfLine::Cr:
return "\r";
default:
return "\n";
}
}
}
// Convert line endings for a piece of text to a particular mode.
// Stop at len or when a NUL is found.
std::string Document::TransformLineEnds(const char *s, size_t len, EndOfLine eolModeWanted) {
std::string dest;
const std::string_view eol = EOLForMode(eolModeWanted);
for (size_t i = 0; (i < len) && (s[i]); i++) {
if (s[i] == '\n' || s[i] == '\r') {
if (eolModeWanted == EndOfLine::Cr) {
dest.push_back('\r');
} else if (eolModeWanted == EndOfLine::Lf) {
dest.push_back('\n');
} else { // eolModeWanted == EndOfLine::CrLf
dest.push_back('\r');
dest.push_back('\n');
}
dest.append(eol);
if ((s[i] == '\r') && (i+1 < len) && (s[i+1] == '\n')) {
i++;
}
@ -1775,13 +1789,7 @@ void Document::ConvertLineEnds(EndOfLine eolModeSet) {
}
std::string_view Document::EOLString() const noexcept {
if (eolMode == EndOfLine::CrLf) {
return "\r\n";
} else if (eolMode == EndOfLine::Cr) {
return "\r";
} else {
return "\n";
}
return EOLForMode(eolMode);
}
DocumentOption Document::Options() const noexcept {

View File

@ -77,6 +77,7 @@ EditModel::EditModel() : braces{} {
hotspotSingleLine = true;
hoverIndicatorPos = Sci::invalidPosition;
wrapWidth = LineLayout::wrapWidthInfinite;
reprs = std::make_unique<SpecialRepresentations>();
pdoc = new Document(DocumentOption::Default);
pdoc->AddRef();
pcs = ContractionStateCreate(pdoc->IsLarge());

View File

@ -27,7 +27,7 @@ public:
int xOffset; ///< Horizontal scrolled amount in pixels
bool trackLineWidth;
SpecialRepresentations reprs;
std::unique_ptr<SpecialRepresentations> reprs;
Caret caret;
SelectionPosition posDrag;
Sci::Position braces[2];

View File

@ -480,7 +480,7 @@ void EditView::LayoutLine(const EditModel &model, Surface *surface, const ViewSt
bool lastSegItalics = false;
std::vector<TextSegment> segments;
BreakFinder bfLayout(ll, nullptr, Range(0, numCharsInLine), posLineStart, 0, BreakFinder::BreakFor::Text, model.pdoc, &model.reprs, nullptr);
BreakFinder bfLayout(ll, nullptr, Range(0, numCharsInLine), posLineStart, 0, BreakFinder::BreakFor::Text, model.pdoc, model.reprs.get(), nullptr);
while (bfLayout.More()) {
segments.push_back(bfLayout.Next());
}
@ -611,7 +611,7 @@ void EditView::UpdateBidiData(const EditModel &model, const ViewStyle &vstyle, L
for (int charsInLine = 0; charsInLine < ll->numCharsInLine; charsInLine++) {
const int charWidth = UTF8DrawBytes(&ll->chars[charsInLine], ll->numCharsInLine - charsInLine);
const Representation *repr = model.reprs.RepresentationFromCharacter(std::string_view(&ll->chars[charsInLine], charWidth));
const Representation *repr = model.reprs->RepresentationFromCharacter(std::string_view(&ll->chars[charsInLine], charWidth));
ll->bidiData->widthReprs[charsInLine] = 0.0f;
if (repr && ll->chars[charsInLine] != '\t') {
@ -1007,12 +1007,12 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle
std::string_view ctrlChar;
Sci::Position widthBytes = 1;
RepresentationAppearance appearance = RepresentationAppearance::Blob;
const Representation *repr = model.reprs.RepresentationFromCharacter(std::string_view(&ll->chars[eolPos], ll->numCharsInLine - eolPos));
const Representation *repr = model.reprs->RepresentationFromCharacter(std::string_view(&ll->chars[eolPos], ll->numCharsInLine - eolPos));
if (repr) {
// Representation of whole text
widthBytes = ll->numCharsInLine - eolPos;
} else {
repr = model.reprs.RepresentationFromCharacter(std::string_view(&ll->chars[eolPos], 1));
repr = model.reprs->RepresentationFromCharacter(std::string_view(&ll->chars[eolPos], 1));
}
if (repr) {
ctrlChar = repr->stringRep;
@ -1666,7 +1666,7 @@ void DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &v
const XYPOSITION xStartVisible = subLineStart - xStart;
const BreakFinder::BreakFor breakFor = selBackDrawn ? BreakFinder::BreakFor::Selection : BreakFinder::BreakFor::Text;
BreakFinder bfBack(ll, &model.sel, lineRange, posLineStart, xStartVisible, breakFor, model.pdoc, &model.reprs, &vsDraw);
BreakFinder bfBack(ll, &model.sel, lineRange, posLineStart, xStartVisible, breakFor, model.pdoc, model.reprs.get(), &vsDraw);
const bool drawWhitespaceBackground = vsDraw.WhitespaceBackgroundDrawn() && !background;
@ -2137,7 +2137,7 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi
// Foreground drawing loop
const BreakFinder::BreakFor breakFor = (((phasesDraw == PhasesDraw::One) && selBackDrawn) || vsDraw.SelectionTextDrawn())
? BreakFinder::BreakFor::ForegroundAndSelection : BreakFinder::BreakFor::Foreground;
BreakFinder bfFore(ll, &model.sel, lineRange, posLineStart, xStartVisible, breakFor, model.pdoc, &model.reprs, &vsDraw);
BreakFinder bfFore(ll, &model.sel, lineRange, posLineStart, xStartVisible, breakFor, model.pdoc, model.reprs.get(), &vsDraw);
while (bfFore.More()) {

View File

@ -217,7 +217,7 @@ void Editor::Finalise() {
}
void Editor::SetRepresentations() {
reprs.SetDefaultRepresentations(pdoc->dbcsCodePage);
reprs->SetDefaultRepresentations(pdoc->dbcsCodePage);
}
void Editor::DropGraphics() noexcept {
@ -2267,6 +2267,21 @@ void Editor::CopyAllowLine() {
CopyToClipboard(selectedText);
}
void Editor::CutAllowLine() {
if (sel.Empty()) {
pdoc->CheckReadOnly();
if (!pdoc->IsReadOnly()) {
SelectionText selectedText;
if (CopyLineRange(&selectedText, false)) {
CopyToClipboard(selectedText);
LineDelete();
}
}
} else {
Cut();
}
}
void Editor::Cut() {
pdoc->CheckReadOnly();
if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) {
@ -2959,6 +2974,7 @@ void Editor::NotifyMacroRecord(Message iMessage, uptr_t wParam, sptr_t lParam) {
case Message::PageDownRectExtend:
case Message::SelectionDuplicate:
case Message::CopyAllowLine:
case Message::CutAllowLine:
case Message::VerticalCentreCaret:
case Message::MoveSelectedLinesUp:
case Message::MoveSelectedLinesDown:
@ -3081,6 +3097,13 @@ void Editor::ChangeCaseOfSelection(CaseMapping caseMapping) {
}
}
void Editor::LineDelete() {
const Sci::Line line = pdoc->SciLineFromPosition(sel.MainCaret());
const Sci::Position start = pdoc->LineStart(line);
const Sci::Position end = pdoc->LineStart(line + 1);
pdoc->DeleteChars(start, end - start);
}
void Editor::LineTranspose() {
const Sci::Line line = pdoc->SciLineFromPosition(sel.MainCaret());
if (line > 0) {
@ -3953,7 +3976,7 @@ int Editor::KeyCommand(Message iMessage) {
AddChar('\f');
break;
case Message::ZoomIn:
if (vs.zoomLevel < 20) {
if (vs.zoomLevel < 60) {
vs.zoomLevel++;
InvalidateStyleRedraw();
NotifyZoom();
@ -3991,12 +4014,8 @@ int Editor::KeyCommand(Message iMessage) {
SetLastXChosen();
}
break;
case Message::LineDelete: {
const Sci::Line line = pdoc->SciLineFromPosition(sel.MainCaret());
const Sci::Position start = pdoc->LineStart(line);
const Sci::Position end = pdoc->LineStart(line + 1);
pdoc->DeleteChars(start, end - start);
}
case Message::LineDelete:
LineDelete();
break;
case Message::LineTranspose:
LineTranspose();
@ -4316,20 +4335,26 @@ std::string Editor::RangeText(Sci::Position start, Sci::Position end) const {
return std::string();
}
void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) {
if (sel.Empty()) {
if (allowLineCopy) {
bool Editor::CopyLineRange(SelectionText *ss, bool allowProtected) {
const Sci::Line currentLine = pdoc->SciLineFromPosition(sel.MainCaret());
const Sci::Position start = pdoc->LineStart(currentLine);
const Sci::Position end = pdoc->LineEnd(currentLine);
if (allowProtected || !RangeContainsProtected(start, end)) {
std::string text = RangeText(start, end);
if (pdoc->eolMode != EndOfLine::Lf)
text.push_back('\r');
if (pdoc->eolMode != EndOfLine::Cr)
text.push_back('\n');
text.append(pdoc->EOLString());
ss->Copy(text, pdoc->dbcsCodePage,
vs.styles[StyleDefault].characterSet, false, true);
return true;
} else {
return false;
}
}
void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) {
if (sel.Empty()) {
if (allowLineCopy) {
CopyLineRange(ss);
}
} else {
std::string text;
@ -4339,10 +4364,7 @@ void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) {
for (const SelectionRange &current : rangesInOrder) {
text.append(RangeText(current.Start().Position(), current.End().Position()));
if (rangesInOrder.size() > 1) {
if (pdoc->eolMode != EndOfLine::Lf)
text.push_back('\r');
if (pdoc->eolMode != EndOfLine::Cr)
text.push_back('\n');
text.append(pdoc->EOLString());
}
}
ss->Copy(text, pdoc->dbcsCodePage,
@ -5158,7 +5180,12 @@ void Editor::TickFor(TickReason reason) {
break;
case TickReason::scroll:
// Auto scroll
if (HaveMouseCapture()) {
ButtonMoveWithModifiers(ptMouseLast, 0, KeyMod::Norm);
} else {
// Capture cancelled so cancel timer
FineTickerCancel(TickReason::scroll);
}
break;
case TickReason::widen:
SetScrollBars();
@ -6183,6 +6210,11 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
CopyAllowLine();
break;
case Message::CutAllowLine:
CutAllowLine();
SetLastXChosen();
break;
case Message::VerticalCentreCaret:
VerticalCentreCaret();
break;
@ -8216,15 +8248,11 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
InvalidateStyleRedraw();
break;
case Message::SetZoom: {
const int zoomLevel = static_cast<int>(wParam);
if (zoomLevel != vs.zoomLevel) {
vs.zoomLevel = zoomLevel;
InvalidateStyleRedraw();
case Message::SetZoom:
if (SetAppearance(vs.zoomLevel, static_cast<int>(wParam))) {
NotifyZoom();
}
break;
}
case Message::GetZoom:
return vs.zoomLevel;
@ -8436,11 +8464,11 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
return vs.controlCharSymbol;
case Message::SetRepresentation:
reprs.SetRepresentation(ConstCharPtrFromUPtr(wParam), ConstCharPtrFromSPtr(lParam));
reprs->SetRepresentation(ConstCharPtrFromUPtr(wParam), ConstCharPtrFromSPtr(lParam));
break;
case Message::GetRepresentation: {
const Representation *repr = reprs.RepresentationFromCharacter(
const Representation *repr = reprs->RepresentationFromCharacter(
ConstCharPtrFromUPtr(wParam));
if (repr) {
return StringResult(lParam, repr->stringRep.c_str());
@ -8449,7 +8477,7 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
}
case Message::ClearRepresentation:
reprs.ClearRepresentation(ConstCharPtrFromUPtr(wParam));
reprs->ClearRepresentation(ConstCharPtrFromUPtr(wParam));
break;
case Message::ClearAllRepresentations:
@ -8457,11 +8485,11 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
break;
case Message::SetRepresentationAppearance:
reprs.SetRepresentationAppearance(ConstCharPtrFromUPtr(wParam), static_cast<RepresentationAppearance>(lParam));
reprs->SetRepresentationAppearance(ConstCharPtrFromUPtr(wParam), static_cast<RepresentationAppearance>(lParam));
break;
case Message::GetRepresentationAppearance: {
const Representation *repr = reprs.RepresentationFromCharacter(
const Representation *repr = reprs->RepresentationFromCharacter(
ConstCharPtrFromUPtr(wParam));
if (repr) {
return static_cast<sptr_t>(repr->appearance);
@ -8469,11 +8497,11 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
return 0;
}
case Message::SetRepresentationColour:
reprs.SetRepresentationColour(ConstCharPtrFromUPtr(wParam), ColourRGBA(static_cast<int>(lParam)));
reprs->SetRepresentationColour(ConstCharPtrFromUPtr(wParam), ColourRGBA(static_cast<int>(lParam)));
break;
case Message::GetRepresentationColour: {
const Representation *repr = reprs.RepresentationFromCharacter(
const Representation *repr = reprs->RepresentationFromCharacter(
ConstCharPtrFromUPtr(wParam));
if (repr) {
return repr->colour.AsInteger();

View File

@ -436,6 +436,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
void PasteRectangular(SelectionPosition pos, const char *ptr, Sci::Position len);
virtual void Copy() = 0;
void CopyAllowLine();
void CutAllowLine();
virtual bool CanPaste();
virtual void Paste() = 0;
void Clear();
@ -481,6 +482,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
enum class CaseMapping { same, upper, lower };
virtual std::string CaseMapString(const std::string &s, CaseMapping caseMapping);
void ChangeCaseOfSelection(CaseMapping caseMapping);
void LineDelete();
void LineTranspose();
void LineReverse();
void Duplicate(bool forLine);
@ -515,6 +517,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
virtual void CopyToClipboard(const SelectionText &selectedText) = 0;
std::string RangeText(Sci::Position start, Sci::Position end) const;
bool CopyLineRange(SelectionText *ss, bool allowProtected=true);
void CopySelectionRange(SelectionText *ss, bool allowLineCopy=false);
void CopyRangeToClipboard(Sci::Position start, Sci::Position end);
void CopyText(size_t length, const char *text);

View File

@ -10,6 +10,7 @@
#include <cstdint>
#include <cassert>
#include <cstring>
#include <cmath>
#include <stdexcept>
#include <string>
@ -273,8 +274,16 @@ void ScintillaBase::AutoCompleteStart(Sci::Position lenEntered, const char *list
ac.options,
};
int lineHeight;
if (vs.autocStyle != StyleDefault) {
AutoSurface surfaceMeasure(this);
lineHeight = static_cast<int>(std::lround(surfaceMeasure->Height(vs.styles[vs.autocStyle].font.get())));
} else {
lineHeight = vs.lineHeight;
}
ac.Start(wMain, idAutoComplete, sel.MainCaret(), PointMainCaret(),
lenEntered, vs.lineHeight, IsUnicodeMode(), technology, options);
lenEntered, lineHeight, IsUnicodeMode(), technology, options);
const PRectangle rcClient = GetClientRectangle();
Point pt = LocationFromPosition(sel.MainCaret() - lenEntered);
@ -307,8 +316,8 @@ void ScintillaBase::AutoCompleteStart(Sci::Position lenEntered, const char *list
rcac.right = rcac.left + widthLB;
rcac.bottom = static_cast<XYPOSITION>(std::min(static_cast<int>(rcac.top) + heightLB, static_cast<int>(rcPopupBounds.bottom)));
ac.lb->SetPositionRelative(rcac, &wMain);
ac.lb->SetFont(vs.styles[StyleDefault].font.get());
const int aveCharWidth = static_cast<int>(vs.styles[StyleDefault].aveCharWidth);
ac.lb->SetFont(vs.styles[vs.autocStyle].font.get());
const int aveCharWidth = static_cast<int>(vs.styles[vs.autocStyle].aveCharWidth);
ac.lb->SetAverageCharWidth(aveCharWidth);
ac.lb->SetDelegate(this);
@ -941,6 +950,14 @@ sptr_t ScintillaBase::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
case Message::AutoCGetMaxWidth:
return maxListWidth;
case Message::AutoCSetStyle:
vs.autocStyle = static_cast<int>(wParam);
InvalidateStyleRedraw();
break;
case Message::AutoCGetStyle:
return vs.autocStyle;
case Message::RegisterImage:
ac.lb->RegisterImage(static_cast<int>(wParam), ConstCharPtrFromSPtr(lParam));
break;

View File

@ -252,6 +252,8 @@ ViewStyle::ViewStyle(size_t stylesSize_) :
ctrlCharPadding = 3; // +3 For a blank on front and rounded edge each side
lastSegItalicsOffset = 2;
autocStyle = StyleDefault;
localeName = localeNameDefault;
}
@ -792,7 +794,8 @@ FontRealised *ViewStyle::Find(const FontSpecification &fs) {
void ViewStyle::FindMaxAscentDescent() noexcept {
for (size_t i = 0; i < styles.size(); i++) {
if (i == StyleCallTip)
if (i == StyleCallTip ||
(autocStyle != StyleDefault && i == static_cast<size_t>(autocStyle)))
continue;
const auto &style = styles[i];

View File

@ -179,6 +179,7 @@ public:
int marginNumberPadding; // the right-side padding of the number margin
int ctrlCharPadding; // the padding around control character text blobs
int lastSegItalicsOffset; // the offset so as not to clip italic characters at EOLs
int autocStyle;
using ElementMap = std::map<Scintilla::Element, ColourOptional>;
ElementMap elementColours;

View File

@ -581,6 +581,19 @@ class TestSimple(unittest.TestCase):
self.ed.EOLMode = lineEndType
self.assertEqual(self.ed.Contents(), b"a1\na1\nb2")
def testCutAllowLine(self):
lineEndType = self.ed.EOLMode
self.ed.EOLMode = self.ed.SC_EOL_LF
self.ed.AddText(5, b"a1\nb2")
self.ed.SetSel(1,1)
self.ed.CutAllowLine()
# Clipboard = "a1\n"
self.assertEqual(self.ed.CanPaste(), 1)
self.ed.SetSel(0, 0)
self.ed.Paste()
self.ed.EOLMode = lineEndType
self.assertEqual(self.ed.Contents(), b"a1\nb2")
def testDuplicate(self):
self.ed.AddText(3, b"1b2")
self.ed.SetSel(1,2)
@ -1868,6 +1881,7 @@ class TestMultiSelection(unittest.TestCase):
self.ed.ClearAll()
self.ed.EmptyUndoBuffer()
# 3 lines of 3 characters
self.ed.EOLMode = self.ed.SC_EOL_CRLF
t = b"xxx\nxxx\nxxx"
self.ed.AddText(len(t), t)
@ -1946,6 +1960,52 @@ class TestMultiSelection(unittest.TestCase):
self.assertEqual(self.ed.GetSelectionNAnchor(2), 9)
self.assertEqual(self.ed.GetSelectionNCaret(2), 10)
def testRectangularCopy(self):
self.ed.RectangularSelectionAnchor = 1
self.assertEqual(self.ed.RectangularSelectionAnchor, 1)
self.ed.RectangularSelectionCaret = 10
self.assertEqual(self.ed.RectangularSelectionCaret, 10)
self.assertEqual(self.ed.Selections, 3)
self.ed.Copy()
self.ed.ClearAll()
self.ed.Paste()
# Single character slice with current line ends
result = b"x\r\nx\r\nx"
self.assertEqual(self.ed.Contents(), result)
def testMultipleCopy(self):
self.ed.ClearAll()
t = b"abc\n123\nxyz"
self.ed.AddText(len(t), t)
self.ed.SetSelection(4, 5) # 1
self.ed.AddSelection(1, 3) # bc
self.ed.AddSelection(10, 11) # z
self.ed.Copy()
# 1,bc,z
self.ed.ClearAll()
self.ed.Paste()
self.assertEqual(self.ed.Contents(), b"1bcz")
def testPasteConversion(self):
# Test that line ends are converted to current mode
self.ed.SetSelection(0, 11)
self.ed.Copy()
self.ed.ClearAll()
self.ed.EOLMode = self.ed.SC_EOL_CRLF
self.ed.Paste()
self.assertEqual(self.ed.Contents(), b"xxx\r\nxxx\r\nxxx")
self.ed.ClearAll()
self.ed.EOLMode = self.ed.SC_EOL_CR
self.ed.Paste()
self.assertEqual(self.ed.Contents(), b"xxx\rxxx\rxxx")
self.ed.ClearAll()
self.ed.EOLMode = self.ed.SC_EOL_LF
self.ed.Paste()
self.assertEqual(self.ed.Contents(), b"xxx\nxxx\nxxx")
def testVirtualSpace(self):
self.ed.SetSelection(3, 7)
self.ed.SetSelectionNCaretVirtualSpace(0, 3)
@ -3093,6 +3153,10 @@ class TestAutoComplete(unittest.TestCase):
self.assertEqual(self.ed.AutoCGetDropRestOfWord(), 1)
self.ed.AutoCSetDropRestOfWord(0)
self.ed.AutoCSetStyle(13)
self.assertEqual(self.ed.AutoCGetStyle(), 13)
self.ed.AutoCSetStyle(self.ed.STYLE_DEFAULT)
def testAutoShow(self):
self.assertEqual(self.ed.AutoCActive(), 0)
self.ed.SetSel(0, 0)

View File

@ -1 +1 @@
550
551

View File

@ -124,12 +124,59 @@ void LoadD2DOnce() noexcept {
}
}
bool LoadD2D() {
bool LoadD2D() noexcept {
static std::once_flag once;
try {
std::call_once(once, LoadD2DOnce);
} catch (...) {
// ignore
}
return pIDWriteFactory && pD2DFactory;
}
constexpr D2D_COLOR_F ColorFromColourAlpha(ColourRGBA colour) noexcept {
return D2D_COLOR_F{
colour.GetRedComponent(),
colour.GetGreenComponent(),
colour.GetBlueComponent(),
colour.GetAlphaComponent()
};
}
using BrushSolid = std::unique_ptr<ID2D1SolidColorBrush, UnknownReleaser>;
BrushSolid BrushSolidCreate(ID2D1RenderTarget *pTarget, COLORREF colour) noexcept {
ID2D1SolidColorBrush *pBrush = nullptr;
const D2D_COLOR_F col = ColorFromColourAlpha(ColourRGBA::FromRGB(colour));
const HRESULT hr = pTarget->CreateSolidColorBrush(col, &pBrush);
if (FAILED(hr) || !pBrush) {
return {};
}
return BrushSolid(pBrush);
}
using Geometry = std::unique_ptr<ID2D1PathGeometry, UnknownReleaser>;
Geometry GeometryCreate() noexcept {
ID2D1PathGeometry *geometry = nullptr;
const HRESULT hr = pD2DFactory->CreatePathGeometry(&geometry);
if (FAILED(hr) || !geometry) {
return {};
}
return Geometry(geometry);
}
using GeometrySink = std::unique_ptr<ID2D1GeometrySink, UnknownReleaser>;
GeometrySink GeometrySinkCreate(ID2D1PathGeometry *geometry) noexcept {
ID2D1GeometrySink *sink = nullptr;
const HRESULT hr = geometry->Open(&sink);
if (FAILED(hr) || !sink) {
return {};
}
return GeometrySink(sink);
}
#endif
void *PointerFromWindow(HWND hWnd) noexcept {
@ -167,9 +214,6 @@ GetWindowDpiAwarenessContextSig fnGetWindowDpiAwarenessContext = nullptr;
using GetScaleFactorForMonitorSig = HRESULT(WINAPI *)(HMONITOR, DEVICE_SCALE_FACTOR *);
GetScaleFactorForMonitorSig fnGetScaleFactorForMonitor = nullptr;
using GetThreadDpiAwarenessContextSig = DPI_AWARENESS_CONTEXT(WINAPI *)();
GetThreadDpiAwarenessContextSig fnGetThreadDpiAwarenessContext = nullptr;
using SetThreadDpiAwarenessContextSig = DPI_AWARENESS_CONTEXT(WINAPI *)(DPI_AWARENESS_CONTEXT);
SetThreadDpiAwarenessContextSig fnSetThreadDpiAwarenessContext = nullptr;
@ -178,7 +222,6 @@ void LoadDpiForWindow() noexcept {
fnGetDpiForWindow = DLLFunction<GetDpiForWindowSig>(user32, "GetDpiForWindow");
fnGetSystemMetricsForDpi = DLLFunction<GetSystemMetricsForDpiSig>(user32, "GetSystemMetricsForDpi");
fnAdjustWindowRectExForDpi = DLLFunction<AdjustWindowRectExForDpiSig>(user32, "AdjustWindowRectExForDpi");
fnGetThreadDpiAwarenessContext = DLLFunction<GetThreadDpiAwarenessContextSig>(user32, "GetThreadDpiAwarenessContext");
fnSetThreadDpiAwarenessContext = DLLFunction<SetThreadDpiAwarenessContextSig>(user32, "SetThreadDpiAwarenessContext");
using GetDpiForSystemSig = UINT(WINAPI *)(void);
@ -1306,15 +1349,6 @@ constexpr Supports SupportsD2D[] = {
Supports::ThreadSafeMeasureWidths,
};
constexpr D2D_COLOR_F ColorFromColourAlpha(ColourRGBA colour) noexcept {
return D2D_COLOR_F{
colour.GetRedComponent(),
colour.GetGreenComponent(),
colour.GetBlueComponent(),
colour.GetAlphaComponent()
};
}
constexpr D2D1_RECT_F RectangleInset(D2D1_RECT_F rect, FLOAT inset) noexcept {
return D2D1_RECT_F{
rect.left + inset,
@ -1374,7 +1408,7 @@ public:
int PixelDivisions() override;
int DeviceHeightFont(int points) override;
void LineDraw(Point start, Point end, Stroke stroke) override;
ID2D1PathGeometry *Geometry(const Point *pts, size_t npts, D2D1_FIGURE_BEGIN figureBegin) noexcept;
static Geometry GeometricFigure(const Point *pts, size_t npts, D2D1_FIGURE_BEGIN figureBegin) noexcept;
void PolyLine(const Point *pts, size_t npts, Stroke stroke) override;
void Polygon(const Point *pts, size_t npts, FillStroke fillStroke) override;
void RectangleDraw(PRectangle rc, FillStroke fillStroke) override;
@ -1584,13 +1618,10 @@ void SurfaceD2D::LineDraw(Point start, Point end, Stroke stroke) {
ReleaseUnknown(pStrokeStyle);
}
ID2D1PathGeometry *SurfaceD2D::Geometry(const Point *pts, size_t npts, D2D1_FIGURE_BEGIN figureBegin) noexcept {
ID2D1PathGeometry *geometry = nullptr;
HRESULT hr = pD2DFactory->CreatePathGeometry(&geometry);
if (SUCCEEDED(hr) && geometry) {
ID2D1GeometrySink *sink = nullptr;
hr = geometry->Open(&sink);
if (SUCCEEDED(hr) && sink) {
Geometry SurfaceD2D::GeometricFigure(const Point *pts, size_t npts, D2D1_FIGURE_BEGIN figureBegin) noexcept {
Geometry geometry = GeometryCreate();
if (geometry) {
if (const GeometrySink sink = GeometrySinkCreate(geometry.get())) {
sink->BeginFigure(DPointFromPoint(pts[0]), figureBegin);
for (size_t i = 1; i < npts; i++) {
sink->AddLine(DPointFromPoint(pts[i]));
@ -1598,7 +1629,6 @@ ID2D1PathGeometry *SurfaceD2D::Geometry(const Point *pts, size_t npts, D2D1_FIGU
sink->EndFigure((figureBegin == D2D1_FIGURE_BEGIN_FILLED) ?
D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN);
sink->Close();
ReleaseUnknown(sink);
}
}
return geometry;
@ -1610,7 +1640,7 @@ void SurfaceD2D::PolyLine(const Point *pts, size_t npts, Stroke stroke) {
return;
}
ID2D1PathGeometry *geometry = Geometry(pts, npts, D2D1_FIGURE_BEGIN_HOLLOW);
const Geometry geometry = GeometricFigure(pts, npts, D2D1_FIGURE_BEGIN_HOLLOW);
PLATFORM_ASSERT(geometry);
if (!geometry) {
return;
@ -1631,23 +1661,21 @@ void SurfaceD2D::PolyLine(const Point *pts, size_t npts, Stroke stroke) {
const HRESULT hr = pD2DFactory->CreateStrokeStyle(
strokeProps, nullptr, 0, &pStrokeStyle);
if (SUCCEEDED(hr)) {
pRenderTarget->DrawGeometry(geometry, pBrush, stroke.WidthF(), pStrokeStyle);
pRenderTarget->DrawGeometry(geometry.get(), pBrush, stroke.WidthF(), pStrokeStyle);
}
ReleaseUnknown(pStrokeStyle);
ReleaseUnknown(geometry);
}
void SurfaceD2D::Polygon(const Point *pts, size_t npts, FillStroke fillStroke) {
PLATFORM_ASSERT(pRenderTarget && (npts > 2));
if (pRenderTarget) {
ID2D1PathGeometry *geometry = Geometry(pts, npts, D2D1_FIGURE_BEGIN_FILLED);
const Geometry geometry = GeometricFigure(pts, npts, D2D1_FIGURE_BEGIN_FILLED);
PLATFORM_ASSERT(geometry);
if (geometry) {
D2DPenColourAlpha(fillStroke.fill.colour);
pRenderTarget->FillGeometry(geometry, pBrush);
pRenderTarget->FillGeometry(geometry.get(), pBrush);
D2DPenColourAlpha(fillStroke.stroke.colour);
pRenderTarget->DrawGeometry(geometry, pBrush, fillStroke.stroke.WidthF());
ReleaseUnknown(geometry);
pRenderTarget->DrawGeometry(geometry.get(), pBrush, fillStroke.stroke.WidthF());
}
}
}
@ -1876,13 +1904,10 @@ void SurfaceD2D::Stadium(PRectangle rc, FillStroke fillStroke, Ends ends) {
PRectangle rcInner = rc;
rcInner.left += radius;
rcInner.right -= radius;
ID2D1PathGeometry *pathGeometry = nullptr;
const HRESULT hrGeometry = pD2DFactory->CreatePathGeometry(&pathGeometry);
if (FAILED(hrGeometry) || !pathGeometry)
const Geometry pathGeometry = GeometryCreate();
if (!pathGeometry)
return;
ID2D1GeometrySink *pSink = nullptr;
const HRESULT hrSink = pathGeometry->Open(&pSink);
if (SUCCEEDED(hrSink) && pSink) {
if (const GeometrySink pSink = GeometrySinkCreate(pathGeometry.get())) {
switch (leftSide) {
case Ends::leftFlat:
pSink->BeginFigure(DPointFromPoint(Point(rc.left + halfStroke, rc.top + halfStroke)), D2D1_FIGURE_BEGIN_FILLED);
@ -1935,12 +1960,10 @@ void SurfaceD2D::Stadium(PRectangle rc, FillStroke fillStroke, Ends ends) {
pSink->Close();
}
ReleaseUnknown(pSink);
D2DPenColourAlpha(fillStroke.fill.colour);
pRenderTarget->FillGeometry(pathGeometry, pBrush);
pRenderTarget->FillGeometry(pathGeometry.get(), pBrush);
D2DPenColourAlpha(fillStroke.stroke.colour);
pRenderTarget->DrawGeometry(pathGeometry, pBrush, fillStroke.stroke.WidthF());
ReleaseUnknown(pathGeometry);
pRenderTarget->DrawGeometry(pathGeometry.get(), pBrush, fillStroke.stroke.WidthF());
}
}
@ -2676,7 +2699,7 @@ void SurfaceD2D::SetRenderingParams(std::shared_ptr<RenderingParams> renderingPa
#endif
std::unique_ptr<Surface> Surface::Allocate(Technology technology) {
std::unique_ptr<Surface> Surface::Allocate([[maybe_unused]] Technology technology) {
#if defined(USE_D2D)
if (technology == Technology::Default)
return std::make_unique<SurfaceGDI>();
@ -2782,110 +2805,278 @@ void Window::InvalidateRectangle(PRectangle rc) {
::InvalidateRect(HwndFromWindowID(wid), &rcw, FALSE);
}
HCURSOR LoadReverseArrowCursor(UINT dpi, int cursorBaseSize) noexcept {
namespace {
std::optional<DWORD> RegGetDWORD(HKEY hKey, LPCWSTR valueName) noexcept {
DWORD value = 0;
DWORD type = REG_NONE;
DWORD size = sizeof(DWORD);
const LSTATUS status = ::RegQueryValueExW(hKey, valueName, nullptr, &type, reinterpret_cast<LPBYTE>(&value), &size);
if (status == ERROR_SUCCESS && type == REG_DWORD) {
return value;
}
return {};
}
class CursorHelper {
HDC hMemDC {};
HBITMAP hBitmap {};
HBITMAP hOldBitmap {};
DWORD *pixels = nullptr;
const int width;
const int height;
static constexpr float arrow[][2] = {
{ 32.0f - 12.73606f,32.0f - 19.04075f },
{ 32.0f - 7.80159f, 32.0f - 19.04075f },
{ 32.0f - 9.82813f, 32.0f - 14.91828f },
{ 32.0f - 6.88341f, 32.0f - 13.42515f },
{ 32.0f - 4.62301f, 32.0f - 18.05872f },
{ 32.0f - 1.26394f, 32.0f - 14.78295f },
{ 32.0f - 1.26394f, 32.0f - 30.57485f },
};
public:
ICONINFO info{};
BITMAP bmp{};
bool HasBitmap() const noexcept {
return bmp.bmWidth > 0;
}
CursorHelper(const HCURSOR cursor) noexcept {
Init(cursor);
}
~CursorHelper() {
CleanUp();
if (hOldBitmap) {
SelectBitmap(hMemDC, hOldBitmap);
}
CursorHelper &operator=(const HCURSOR cursor) noexcept {
CleanUp();
Init(cursor);
return *this;
if (hBitmap) {
::DeleteObject(hBitmap);
}
bool MatchesSize(const int width, const int height) noexcept {
return bmp.bmWidth == width && bmp.bmHeight == height;
}
HCURSOR CreateFlippedCursor() noexcept {
if (info.hbmMask)
FlipBitmap(info.hbmMask, bmp.bmWidth, bmp.bmHeight);
if (info.hbmColor)
FlipBitmap(info.hbmColor, bmp.bmWidth, bmp.bmHeight);
info.xHotspot = bmp.bmWidth - 1 - info.xHotspot;
return ::CreateIconIndirect(&info);
}
private:
void Init(const HCURSOR &cursor) noexcept {
if (::GetIconInfo(cursor, &info)) {
::GetObject(info.hbmMask, sizeof(bmp), &bmp);
PLATFORM_ASSERT(HasBitmap());
if (hMemDC) {
::DeleteDC(hMemDC);
}
}
void CleanUp() noexcept {
if (info.hbmMask)
::DeleteObject(info.hbmMask);
if (info.hbmColor)
::DeleteObject(info.hbmColor);
info = {};
bmp = {};
CursorHelper(int width_, int height_) noexcept : width{width_}, height{height_} {
hMemDC = ::CreateCompatibleDC({});
if (!hMemDC) {
return;
}
static void FlipBitmap(const HBITMAP bitmap, const int width, const int height) noexcept {
HDC hdc = ::CreateCompatibleDC({});
if (hdc) {
HBITMAP prevBmp = SelectBitmap(hdc, bitmap);
::StretchBlt(hdc, width - 1, 0, -width, height, hdc, 0, 0, width, height, SRCCOPY);
SelectBitmap(hdc, prevBmp);
::DeleteDC(hdc);
// https://learn.microsoft.com/en-us/windows/win32/menurc/using-cursors#creating-a-cursor
BITMAPV5HEADER bi {};
bi.bV5Size = sizeof(BITMAPV5HEADER);
bi.bV5Width = width;
bi.bV5Height = height;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
// The following mask specification specifies a supported 32 BPP alpha format for Windows XP.
bi.bV5RedMask = 0x00FF0000U;
bi.bV5GreenMask = 0x0000FF00U;
bi.bV5BlueMask = 0x000000FFU;
bi.bV5AlphaMask = 0xFF000000U;
// Create the DIB section with an alpha channel.
hBitmap = CreateDIBSection(hMemDC, reinterpret_cast<BITMAPINFO *>(&bi), DIB_RGB_COLORS, reinterpret_cast<void **>(&pixels), nullptr, 0);
if (hBitmap) {
hOldBitmap = SelectBitmap(hMemDC, hBitmap);
}
}
bool HasBitmap() const noexcept {
return hOldBitmap != nullptr;
}
HCURSOR Create() noexcept {
HCURSOR cursor {};
// Create an empty mask bitmap.
HBITMAP hMonoBitmap = ::CreateBitmap(width, height, 1, 1, nullptr);
if (hMonoBitmap) {
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createiconindirect
// hBitmap should not already be selected into a device context
SelectBitmap(hMemDC, hOldBitmap);
hOldBitmap = {};
ICONINFO info = {false, static_cast<DWORD>(width - 1), 0, hMonoBitmap, hBitmap};
cursor = ::CreateIconIndirect(&info);
::DeleteObject(hMonoBitmap);
}
return cursor;
}
#if defined(USE_D2D)
bool DrawD2D(COLORREF fillColour, COLORREF strokeColour) noexcept {
if (!LoadD2D()) {
return false;
}
D2D1_RENDER_TARGET_PROPERTIES drtp {};
drtp.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
drtp.usage = D2D1_RENDER_TARGET_USAGE_NONE;
drtp.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
drtp.dpiX = 96.f;
drtp.dpiY = 96.f;
drtp.pixelFormat = D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_PREMULTIPLIED
);
ID2D1DCRenderTarget *pTarget_ = nullptr;
HRESULT hr = pD2DFactory->CreateDCRenderTarget(&drtp, &pTarget_);
if (FAILED(hr) || !pTarget_) {
return false;
}
const std::unique_ptr<ID2D1DCRenderTarget, UnknownReleaser> pTarget(pTarget_);
const RECT rc = {0, 0, width, height};
hr = pTarget_->BindDC(hMemDC, &rc);
if (FAILED(hr)) {
return false;
}
pTarget->BeginDraw();
// Draw something on the bitmap section.
constexpr size_t nPoints = std::size(arrow);
D2D1_POINT_2F points[nPoints]{};
const FLOAT scale = width/32.0f;
for (size_t i = 0; i < nPoints; i++) {
points[i].x = arrow[i][0] * scale;
points[i].y = arrow[i][1] * scale;
}
const Geometry geometry = GeometryCreate();
if (!geometry) {
return false;
}
const GeometrySink sink = GeometrySinkCreate(geometry.get());
if (!sink) {
return false;
}
sink->BeginFigure(points[0], D2D1_FIGURE_BEGIN_FILLED);
for (size_t i = 1; i < nPoints; i++) {
sink->AddLine(points[i]);
}
sink->EndFigure(D2D1_FIGURE_END_CLOSED);
hr = sink->Close();
if (FAILED(hr)) {
return false;
}
if (const BrushSolid pBrushFill = BrushSolidCreate(pTarget.get(), fillColour)) {
pTarget->FillGeometry(geometry.get(), pBrushFill.get());
}
if (const BrushSolid pBrushStroke = BrushSolidCreate(pTarget.get(), strokeColour)) {
pTarget->DrawGeometry(geometry.get(), pBrushStroke.get(), scale);
}
hr = pTarget->EndDraw();
return SUCCEEDED(hr);
}
#endif
void Draw(COLORREF fillColour, COLORREF strokeColour) noexcept {
#if defined(USE_D2D)
if (DrawD2D(fillColour, strokeColour)) {
return;
}
#endif
// Draw something on the DIB section.
constexpr size_t nPoints = std::size(arrow);
POINT points[nPoints]{};
const float scale = width/32.0f;
for (size_t i = 0; i < nPoints; i++) {
points[i].x = std::lround(arrow[i][0] * scale);
points[i].y = std::lround(arrow[i][1] * scale);
}
const DWORD penWidth = std::lround(scale);
HPEN pen;
if (penWidth > 1) {
const LOGBRUSH brushParameters { BS_SOLID, strokeColour, 0 };
pen = ::ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_ROUND | PS_JOIN_MITER,
penWidth,
&brushParameters,
0,
nullptr);
} else {
pen = ::CreatePen(PS_INSIDEFRAME, 1, strokeColour);
}
HPEN penOld = SelectPen(hMemDC, pen);
HBRUSH brush = ::CreateSolidBrush(fillColour);
HBRUSH brushOld = SelectBrush(hMemDC, brush);
::Polygon(hMemDC, points, static_cast<int>(nPoints));
SelectPen(hMemDC, penOld);
SelectBrush(hMemDC, brushOld);
::DeleteObject(pen);
::DeleteObject(brush);
// Set the alpha values for each pixel in the cursor.
for (int i = 0; i < width*height; i++) {
if (*pixels != 0) {
*pixels |= 0xFF000000U;
}
pixels++;
}
}
};
HCURSOR reverseArrowCursor {};
}
int width;
int height;
HCURSOR LoadReverseArrowCursor(UINT dpi) noexcept {
// https://learn.microsoft.com/en-us/answers/questions/815036/windows-cursor-size
constexpr DWORD defaultCursorBaseSize = 32;
constexpr DWORD maxCursorBaseSize = 16*(1 + 15); // 16*(1 + CursorSize)
DWORD cursorBaseSize = 0;
HKEY hKey {};
LSTATUS status = ::RegOpenKeyExW(HKEY_CURRENT_USER, L"Control Panel\\Cursors", 0, KEY_QUERY_VALUE, &hKey);
if (status == ERROR_SUCCESS) {
if (std::optional<DWORD> baseSize = RegGetDWORD(hKey, L"CursorBaseSize")) {
// CursorBaseSize is multiple of 16
cursorBaseSize = std::min(*baseSize & ~15, maxCursorBaseSize);
}
::RegCloseKey(hKey);
}
int width = 0;
int height = 0;
if (cursorBaseSize > defaultCursorBaseSize) {
width = ::MulDiv(cursorBaseSize, dpi, USER_DEFAULT_SCREEN_DPI);
height = width;
} else {
width = SystemMetricsForDpi(SM_CXCURSOR, dpi);
height = SystemMetricsForDpi(SM_CYCURSOR, dpi);
PLATFORM_ASSERT(width == height);
}
DPI_AWARENESS_CONTEXT oldContext = nullptr;
if (fnAreDpiAwarenessContextsEqual && fnAreDpiAwarenessContextsEqual(fnGetThreadDpiAwarenessContext(), DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) {
oldContext = fnSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
PLATFORM_ASSERT(oldContext != nullptr);
CursorHelper cursorHelper(width, height);
if (!cursorHelper.HasBitmap()) {
return {};
}
const HCURSOR cursor = static_cast<HCURSOR>(::LoadImage({}, IDC_ARROW, IMAGE_CURSOR, width, height, LR_SHARED));
if (cursor) {
CursorHelper cursorHelper(cursor);
if (cursorHelper.HasBitmap() && !cursorHelper.MatchesSize(width, height)) {
const HCURSOR copy = static_cast<HCURSOR>(::CopyImage(cursor, IMAGE_CURSOR, width, height, LR_COPYFROMRESOURCE | LR_COPYRETURNORG));
if (copy) {
cursorHelper = copy;
::DestroyCursor(copy);
COLORREF fillColour = RGB(0xff, 0xff, 0xfe);
COLORREF strokeColour = RGB(0, 0, 1);
status = ::RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Accessibility", 0, KEY_QUERY_VALUE, &hKey);
if (status == ERROR_SUCCESS) {
if (std::optional<DWORD> cursorType = RegGetDWORD(hKey, L"CursorType")) {
switch (*cursorType) {
case 1: // black
case 4: // black
std::swap(fillColour, strokeColour);
break;
case 6: // custom
if (std::optional<DWORD> cursorColor = RegGetDWORD(hKey, L"CursorColor")) {
fillColour = *cursorColor;
}
break;
default: // 0, 3 white, 2, 5 invert
break;
}
}
::RegCloseKey(hKey);
}
if (cursorHelper.HasBitmap()) {
reverseArrowCursor = cursorHelper.CreateFlippedCursor();
}
}
if (oldContext) {
fnSetThreadDpiAwarenessContext(oldContext);
}
return reverseArrowCursor;
cursorHelper.Draw(fillColour, strokeColour);
HCURSOR cursor = cursorHelper.Create();
return cursor;
}
void Window::SetCursor(Cursor curs) {
@ -2911,6 +3102,7 @@ void Window::SetCursor(Cursor curs) {
case Cursor::reverseArrow:
case Cursor::arrow:
case Cursor::invalid: // Should not occur, but just in case.
default:
::SetCursor(::LoadCursor(NULL,IDC_ARROW));
break;
}

View File

@ -50,8 +50,7 @@ float GetDeviceScaleFactorWhenGdiScalingActive(HWND hWnd) noexcept;
int SystemMetricsForDpi(int nIndex, UINT dpi) noexcept;
constexpr int defaultCursorBaseSize = 32;
HCURSOR LoadReverseArrowCursor(UINT dpi, int cursorBaseSize) noexcept;
HCURSOR LoadReverseArrowCursor(UINT dpi) noexcept;
class MouseWheelDelta {
int wheelDelta = 0;
@ -68,7 +67,7 @@ public:
};
#if defined(USE_D2D)
extern bool LoadD2D();
extern bool LoadD2D() noexcept;
extern ID2D1Factory *pD2DFactory;
extern IDWriteFactory *pIDWriteFactory;

View File

@ -4,8 +4,8 @@
#include <windows.h>
#define VERSION_SCINTILLA "5.5.0"
#define VERSION_WORDS 5, 5, 0, 0
#define VERSION_SCINTILLA "5.5.1"
#define VERSION_WORDS 5, 5, 1, 0
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_WORDS

View File

@ -326,9 +326,8 @@ public:
class GlobalMemory;
class ReverseArrowCursor {
UINT dpi = USER_DEFAULT_SCREEN_DPI;
UINT cursorBaseSize = defaultCursorBaseSize;
HCURSOR cursor {};
bool valid = false;
public:
ReverseArrowCursor() noexcept {}
@ -343,17 +342,20 @@ public:
}
}
HCURSOR Load(UINT dpi_, UINT cursorBaseSize_) noexcept {
void Invalidate() noexcept {
valid = false;
}
HCURSOR Load(UINT dpi) noexcept {
if (cursor) {
if (dpi == dpi_ && cursorBaseSize == cursorBaseSize_) {
if (valid) {
return cursor;
}
::DestroyCursor(cursor);
}
dpi = dpi_;
cursorBaseSize = cursorBaseSize_;
cursor = LoadReverseArrowCursor(dpi_, cursorBaseSize_);
valid = true;
cursor = LoadReverseArrowCursor(dpi);
return cursor ? cursor : ::LoadCursor({}, IDC_ARROW);
}
};
@ -394,7 +396,6 @@ class ScintillaWin :
MouseWheelDelta horizontalWheelDelta;
UINT dpi = USER_DEFAULT_SCREEN_DPI;
UINT cursorBaseSize = defaultCursorBaseSize;
ReverseArrowCursor reverseArrowCursor;
PRectangle rectangleClient;
@ -627,7 +628,7 @@ ScintillaWin::ScintillaWin(HWND hwnd) {
cfColumnSelect = RegisterClipboardType(L"MSDEVColumnSelect");
cfBorlandIDEBlockType = RegisterClipboardType(L"Borland IDE Block Type");
// Likewise for line-copy (copies a full line when no text is selected)
// Likewise for line-copy or line-cut (copies or cuts a full line when no text is selected)
cfLineSelect = RegisterClipboardType(L"MSDEVLineSelect");
cfVSLineTag = RegisterClipboardType(L"VisualStudioEditorOperationsLineCutCopyClipboardTag");
hrOle = E_FAIL;
@ -827,7 +828,7 @@ void ScintillaWin::DisplayCursor(Window::Cursor c) {
c = static_cast<Window::Cursor>(cursorMode);
}
if (c == Window::Cursor::reverseArrow) {
::SetCursor(reverseArrowCursor.Load(static_cast<UINT>(dpi * deviceScaleFactor), cursorBaseSize));
::SetCursor(reverseArrowCursor.Load(static_cast<UINT>(dpi * deviceScaleFactor)));
} else {
wMain.SetCursor(c);
}
@ -2192,6 +2193,7 @@ sptr_t ScintillaWin::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
case WM_DPICHANGED:
dpi = HIWORD(wParam);
reverseArrowCursor.Invalidate();
InvalidateStyleRedraw();
break;
@ -2199,6 +2201,7 @@ sptr_t ScintillaWin::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
const UINT dpiNow = DpiForWindow(wMain.GetID());
if (dpi != dpiNow) {
dpi = dpiNow;
reverseArrowCursor.Invalidate();
InvalidateStyleRedraw();
}
}
@ -2807,6 +2810,27 @@ bool OpenClipboardRetry(HWND hwnd) noexcept {
return false;
}
// Ensure every successful OpenClipboard is followed by a CloseClipboard.
class Clipboard {
bool opened = false;
public:
Clipboard(HWND hwnd) noexcept : opened(::OpenClipboardRetry(hwnd)) {
}
// Deleted so Clipboard objects can not be copied.
Clipboard(const Clipboard &) = delete;
Clipboard(Clipboard &&) = delete;
Clipboard &operator=(const Clipboard &) = delete;
Clipboard &operator=(Clipboard &&) = delete;
~Clipboard() noexcept {
if (opened) {
::CloseClipboard();
}
}
constexpr operator bool() const noexcept {
return opened;
}
};
bool IsValidFormatEtc(const FORMATETC *pFE) noexcept {
return pFE->ptd == nullptr &&
(pFE->dwAspect & DVASPECT_CONTENT) != 0 &&
@ -2822,7 +2846,8 @@ bool SupportedFormat(const FORMATETC *pFE) noexcept {
}
void ScintillaWin::Paste() {
if (!::OpenClipboardRetry(MainHWND())) {
Clipboard clipboard(MainHWND());
if (!clipboard) {
return;
}
UndoGroup ug(pdoc);
@ -2848,7 +2873,6 @@ void ScintillaWin::Paste() {
InsertPasteShape(putf.c_str(), putf.length(), pasteShape);
memUSelection.Unlock();
}
::CloseClipboard();
Redraw();
}
@ -3277,6 +3301,8 @@ LRESULT ScintillaWin::ImeOnDocumentFeed(LPARAM lParam) const {
}
void ScintillaWin::GetMouseParameters() noexcept {
// mouse pointer size and colour may changed
reverseArrowCursor.Invalidate();
// This retrieves the number of lines per scroll as configured in the Mouse Properties sheet in Control Panel
::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &charsPerScroll, 0)) {
@ -3284,20 +3310,6 @@ void ScintillaWin::GetMouseParameters() noexcept {
charsPerScroll = (linesPerScroll == WHEEL_PAGESCROLL) ? 3 : linesPerScroll;
}
::SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &typingWithoutCursor, 0);
// https://learn.microsoft.com/en-us/answers/questions/815036/windows-cursor-size
HKEY hKey;
LSTATUS status = ::RegOpenKeyExW(HKEY_CURRENT_USER, L"Control Panel\\Cursors", 0, KEY_READ, &hKey);
if (status == ERROR_SUCCESS) {
DWORD baseSize = 0;
DWORD type = REG_DWORD;
DWORD size = sizeof(DWORD);
status = ::RegQueryValueExW(hKey, L"CursorBaseSize", nullptr, &type, reinterpret_cast<LPBYTE>(&baseSize), &size);
if (status == ERROR_SUCCESS && type == REG_DWORD) {
cursorBaseSize = baseSize;
}
::RegCloseKey(hKey);
}
}
void ScintillaWin::CopyToGlobal(GlobalMemory &gmUnicode, const SelectionText &selectedText) {
@ -3324,7 +3336,8 @@ void ScintillaWin::CopyToGlobal(GlobalMemory &gmUnicode, const SelectionText &se
}
void ScintillaWin::CopyToClipboard(const SelectionText &selectedText) {
if (!::OpenClipboardRetry(MainHWND())) {
Clipboard clipboard(MainHWND());
if (!clipboard) {
return;
}
::EmptyClipboard();
@ -3350,8 +3363,6 @@ void ScintillaWin::CopyToClipboard(const SelectionText &selectedText) {
::SetClipboardData(cfLineSelect, 0);
::SetClipboardData(cfVSLineTag, 0);
}
::CloseClipboard();
}
void ScintillaWin::ScrollMessage(WPARAM wParam) {