Update Scintilla from 5.2.1 to 5.2.2 and Lexilla from 5.1.5 to 5.1.6

Close #11537
This commit is contained in:
Christian Grasser 2022-04-13 13:10:12 +02:00 committed by Don Ho
parent 3b0d5242ac
commit 100d45f7cf
62 changed files with 1077 additions and 383 deletions

View File

@ -19,6 +19,7 @@
**.def text **.def text
**.manifest text **.manifest text
**.properties text **.properties text
**.session text
**.styled text **.styled text
**.folded text **.folded text
**.adoc text **.adoc text

View File

@ -55,7 +55,7 @@ std::wstring WideStringFromUTF8(std::string_view sv) {
const int sLength = static_cast<int>(sv.length()); const int sLength = static_cast<int>(sv.length());
const int cchWide = ::MultiByteToWideChar(CP_UTF8, 0, sv.data(), sLength, nullptr, 0); const int cchWide = ::MultiByteToWideChar(CP_UTF8, 0, sv.data(), sLength, nullptr, 0);
std::wstring sWide(cchWide, 0); std::wstring sWide(cchWide, 0);
::MultiByteToWideChar(CP_UTF8, 0, sv.data(), sLength, &sWide[0], cchWide); ::MultiByteToWideChar(CP_UTF8, 0, sv.data(), sLength, sWide.data(), cchWide);
return sWide; return sWide;
} }

View File

@ -9,7 +9,7 @@
<meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" /> <meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" />
<meta name="Description" <meta name="Description"
content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." /> content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." />
<meta name="Date.Modified" content="20220209" /> <meta name="Date.Modified" content="20220331" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css"> <style type="text/css">
.logo { .logo {
@ -61,8 +61,8 @@
<font color="#FFCC99" size="4"> A library of language lexers for use with Scintilla</font> <font color="#FFCC99" size="4"> A library of language lexers for use with Scintilla</font>
</td> </td>
<td width="40%" align="right"> <td width="40%" align="right">
<font color="#FFCC99" size="3">Release version 5.1.5<br /> <font color="#FFCC99" size="3">Release version 5.1.6<br />
Site last modified February 9 2022</font> Site last modified March 31 2022</font>
</td> </td>
<td width="20%"> <td width="20%">
&nbsp; &nbsp;
@ -77,6 +77,7 @@
</tr> </tr>
</table> </table>
<ul id="versionlist"> <ul id="versionlist">
<li>Version 5.1.6 improves Markdown and Ruby.</li>
<li>Version 5.1.5 improves Bash, Batch, F#, HTML, Inno Setup, and Python.</li> <li>Version 5.1.5 improves Bash, Batch, F#, HTML, Inno Setup, and Python.</li>
<li>Version 5.1.4 adds lexers for AsciiDoc and GDScript.</li> <li>Version 5.1.4 adds lexers for AsciiDoc and GDScript.</li>
<li>Version 5.1.3 improves Rust.</li> <li>Version 5.1.3 improves Rust.</li>

View File

@ -26,9 +26,9 @@
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0"> <table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
<tr> <tr>
<td> <td>
<font size="4"> <a href="https://www.scintilla.org/lexilla515.zip"> <font size="4"> <a href="https://www.scintilla.org/lexilla516.zip">
Windows</a>&nbsp;&nbsp; Windows</a>&nbsp;&nbsp;
<a href="https://www.scintilla.org/lexilla515.tgz"> <a href="https://www.scintilla.org/lexilla516.tgz">
GTK/Linux</a>&nbsp;&nbsp; GTK/Linux</a>&nbsp;&nbsp;
</font> </font>
</td> </td>
@ -42,7 +42,7 @@
containing very few restrictions. containing very few restrictions.
</p> </p>
<h3> <h3>
Release 5.1.5 Release 5.1.6
</h3> </h3>
<h4> <h4>
Source Code Source Code
@ -50,8 +50,8 @@
The source code package contains all of the source code for Lexilla but no binary The source code package contains all of the source code for Lexilla but no binary
executable code and is available in executable code and is available in
<ul> <ul>
<li><a href="https://www.scintilla.org/lexilla515.zip">zip format</a> (1.1M) commonly used on Windows</li> <li><a href="https://www.scintilla.org/lexilla516.zip">zip format</a> (1.1M) commonly used on Windows</li>
<li><a href="https://www.scintilla.org/lexilla515.tgz">tgz format</a> (0.9M) commonly used on Linux and compatible operating systems</li> <li><a href="https://www.scintilla.org/lexilla516.tgz">tgz format</a> (0.9M) commonly used on Linux and compatible operating systems</li>
</ul> </ul>
Instructions for building on both Windows and Linux are included in the readme file. Instructions for building on both Windows and Linux are included in the readme file.
<h4> <h4>

View File

@ -577,6 +577,7 @@
<td>Arkadiusz Michalski</td> <td>Arkadiusz Michalski</td>
</tr><tr> </tr><tr>
<td>Red_M</td> <td>Red_M</td>
<td>cdbdev</td>
</tr> </tr>
</table> </table>
<h2>Releases</h2> <h2>Releases</h2>
@ -585,13 +586,49 @@
</h3> </h3>
<ul> <ul>
<li> <li>
Released 9 February 2022. Released 31 March 2022.
</li>
<li>
Implement conditional statements "if" and "match", comparison function "$(=", and "FileNameExt"
property in TestLexers to allow varying lexer properties over different files.
<a href="https://github.com/ScintillaOrg/lexilla/issues/62">Issue #62</a>.
</li> </li>
<li> <li>
Add LexAccessor::BufferStyleAt to retrieve style values to simplify logic and Add LexAccessor::BufferStyleAt to retrieve style values to simplify logic and
improve performance. improve performance.
<a href="https://github.com/ScintillaOrg/lexilla/issues/54">Issue #54</a>. <a href="https://github.com/ScintillaOrg/lexilla/issues/54">Issue #54</a>.
</li> </li>
<li>
Markdown: Optionally style all of Markdown header lines.
Enabled with lexer.markdown.header.eolfill=1.
<a href="https://github.com/ScintillaOrg/lexilla/issues/60">Issue #60</a>.
</li>
<li>
Ruby: Fix operator method styling so next word not treated as method name.
<a href="https://github.com/ScintillaOrg/lexilla/issues/65">Issue #65</a>.
</li>
<li>
Ruby: Fix folding for Ruby 3 endless method definition.
<a href="https://github.com/ScintillaOrg/lexilla/issues/65">Issue #65</a>.
</li>
<li>
Ruby: Fold string array SCE_RB_STRING_QW.
<a href="https://github.com/ScintillaOrg/lexilla/issues/65">Issue #65</a>.
</li>
<li>
Ruby: Fix final \n in indented heredoc to be SCE_RB_HERE_Q.
<a href="https://github.com/ScintillaOrg/lexilla/issues/66">Issue #66</a>.
</li>
<li>
Ruby: Fix heredoc recognition when '.' and ',' used in method calls and after SCE_RB_GLOBAL.
Classify word after heredoc delimiter instead of styling as keyword.
<a href="https://github.com/ScintillaOrg/lexilla/issues/67">Issue #67</a>.
</li>
<li>
Ruby: Improve method highlighting so method name is styled as SCE_RB_DEFNAME and class/object
is styled appropriately.
<a href="https://github.com/ScintillaOrg/lexilla/issues/68">Issue #68</a>.
</li>
</ul> </ul>
<h3> <h3>
<a href="https://www.scintilla.org/lexilla515.zip">Release 5.1.5</a> <a href="https://www.scintilla.org/lexilla515.zip">Release 5.1.5</a>

View File

@ -66,6 +66,7 @@ constexpr bool IsNewline(const int ch) {
} }
// True if can follow ch down to the end with possibly trailing whitespace // True if can follow ch down to the end with possibly trailing whitespace
// Does not set the state SCE_MARKDOWN_LINE_BEGIN as to allow further processing
static bool FollowToLineEnd(const int ch, const int state, const Sci_PositionU endPos, StyleContext &sc) { static bool FollowToLineEnd(const int ch, const int state, const Sci_PositionU endPos, StyleContext &sc) {
Sci_Position i = 0; Sci_Position i = 0;
while (sc.GetRelative(++i) == ch) while (sc.GetRelative(++i) == ch)
@ -74,9 +75,8 @@ static bool FollowToLineEnd(const int ch, const int state, const Sci_PositionU e
while (IsASpaceOrTab(sc.GetRelative(i)) && sc.currentPos + i < endPos) while (IsASpaceOrTab(sc.GetRelative(i)) && sc.currentPos + i < endPos)
++i; ++i;
if (IsNewline(sc.GetRelative(i)) || sc.currentPos + i == endPos) { if (IsNewline(sc.GetRelative(i)) || sc.currentPos + i == endPos) {
sc.SetState(state);
sc.Forward(i); sc.Forward(i);
sc.ChangeState(state);
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
return true; return true;
} }
else return false; else return false;
@ -176,6 +176,10 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
// in the default state. // in the default state.
bool freezeCursor = false; bool freezeCursor = false;
// property lexer.markdown.header.eolfill
// Set to 1 to highlight all ATX header text.
bool headerEOLFill = styler.GetPropertyInt("lexer.markdown.header.eolfill", 0) == 1;
StyleContext sc(startPos, static_cast<Sci_PositionU>(length), initStyle, styler); StyleContext sc(startPos, static_cast<Sci_PositionU>(length), initStyle, styler);
while (sc.More()) { while (sc.More()) {
@ -265,22 +269,45 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
} }
else if (sc.state == SCE_MARKDOWN_LINE_BEGIN) { else if (sc.state == SCE_MARKDOWN_LINE_BEGIN) {
// Header // Header
if (sc.Match("######")) if (sc.Match("######")) {
if (headerEOLFill)
sc.SetState(SCE_MARKDOWN_HEADER6);
else
SetStateAndZoom(SCE_MARKDOWN_HEADER6, 6, '#', sc); SetStateAndZoom(SCE_MARKDOWN_HEADER6, 6, '#', sc);
else if (sc.Match("#####")) }
else if (sc.Match("#####")) {
if (headerEOLFill)
sc.SetState(SCE_MARKDOWN_HEADER5);
else
SetStateAndZoom(SCE_MARKDOWN_HEADER5, 5, '#', sc); SetStateAndZoom(SCE_MARKDOWN_HEADER5, 5, '#', sc);
else if (sc.Match("####")) }
else if (sc.Match("####")) {
if (headerEOLFill)
sc.SetState(SCE_MARKDOWN_HEADER4);
else
SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc); SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc);
else if (sc.Match("###")) }
else if (sc.Match("###")) {
if (headerEOLFill)
sc.SetState(SCE_MARKDOWN_HEADER3);
else
SetStateAndZoom(SCE_MARKDOWN_HEADER3, 3, '#', sc); SetStateAndZoom(SCE_MARKDOWN_HEADER3, 3, '#', sc);
else if (sc.Match("##")) }
else if (sc.Match("##")) {
if (headerEOLFill)
sc.SetState(SCE_MARKDOWN_HEADER2);
else
SetStateAndZoom(SCE_MARKDOWN_HEADER2, 2, '#', sc); SetStateAndZoom(SCE_MARKDOWN_HEADER2, 2, '#', sc);
}
else if (sc.Match("#")) { else if (sc.Match("#")) {
// Catch the special case of an unordered list // Catch the special case of an unordered list
if (sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) { if (sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) {
precharCount = 0; precharCount = 0;
sc.SetState(SCE_MARKDOWN_PRECHAR); sc.SetState(SCE_MARKDOWN_PRECHAR);
} }
else if (headerEOLFill) {
sc.SetState(SCE_MARKDOWN_HEADER1);
}
else else
SetStateAndZoom(SCE_MARKDOWN_HEADER1, 1, '#', sc); SetStateAndZoom(SCE_MARKDOWN_HEADER1, 1, '#', sc);
} }
@ -292,14 +319,18 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
sc.SetState(SCE_MARKDOWN_DEFAULT); sc.SetState(SCE_MARKDOWN_DEFAULT);
} }
else if (sc.ch == '=') { else if (sc.ch == '=') {
if (HasPrevLineContent(sc) && FollowToLineEnd('=', SCE_MARKDOWN_HEADER1, endPos, sc)) if (HasPrevLineContent(sc) && FollowToLineEnd('=', SCE_MARKDOWN_HEADER1, endPos, sc)) {
; if (!headerEOLFill)
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
}
else else
sc.SetState(SCE_MARKDOWN_DEFAULT); sc.SetState(SCE_MARKDOWN_DEFAULT);
} }
else if (sc.ch == '-') { else if (sc.ch == '-') {
if (HasPrevLineContent(sc) && FollowToLineEnd('-', SCE_MARKDOWN_HEADER2, endPos, sc)) if (HasPrevLineContent(sc) && FollowToLineEnd('-', SCE_MARKDOWN_HEADER2, endPos, sc)) {
; if (!headerEOLFill)
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
}
else { else {
precharCount = 0; precharCount = 0;
sc.SetState(SCE_MARKDOWN_PRECHAR); sc.SetState(SCE_MARKDOWN_PRECHAR);
@ -317,7 +348,13 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
else if (sc.state == SCE_MARKDOWN_HEADER1 || sc.state == SCE_MARKDOWN_HEADER2 || else if (sc.state == SCE_MARKDOWN_HEADER1 || sc.state == SCE_MARKDOWN_HEADER2 ||
sc.state == SCE_MARKDOWN_HEADER3 || sc.state == SCE_MARKDOWN_HEADER4 || sc.state == SCE_MARKDOWN_HEADER3 || sc.state == SCE_MARKDOWN_HEADER4 ||
sc.state == SCE_MARKDOWN_HEADER5 || sc.state == SCE_MARKDOWN_HEADER6) { sc.state == SCE_MARKDOWN_HEADER5 || sc.state == SCE_MARKDOWN_HEADER6) {
if (IsNewline(sc.ch)) if (headerEOLFill) {
if (sc.atLineStart) {
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
freezeCursor = true;
}
}
else if (IsNewline(sc.ch))
sc.SetState(SCE_MARKDOWN_LINE_BEGIN); sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
} }
@ -420,7 +457,8 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
// Emphasis // Emphasis
else if (sc.ch == '*' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "*")) { else if (sc.ch == '*' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "*")) {
sc.SetState(SCE_MARKDOWN_EM1); sc.SetState(SCE_MARKDOWN_EM1);
} else if (sc.ch == '_' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "_")) { }
else if (sc.ch == '_' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "_")) {
sc.SetState(SCE_MARKDOWN_EM2); sc.SetState(SCE_MARKDOWN_EM2);
} }
// Strikeout // Strikeout

View File

@ -102,7 +102,7 @@ static bool keywordIsModifier(const char *word,
Sci_Position pos, Sci_Position pos,
Accessor &styler); Accessor &styler);
static int ClassifyWordRb(Sci_PositionU start, Sci_PositionU end, WordList &keywords, Accessor &styler, char *prevWord) { static int ClassifyWordRb(Sci_PositionU start, Sci_PositionU end, char ch, WordList &keywords, Accessor &styler, char *prevWord) {
char s[MAX_KEYWORD_LENGTH]; char s[MAX_KEYWORD_LENGTH];
Sci_PositionU i, j; Sci_PositionU i, j;
Sci_PositionU lim = end - start + 1; // num chars to copy Sci_PositionU lim = end - start + 1; // num chars to copy
@ -113,13 +113,22 @@ static int ClassifyWordRb(Sci_PositionU start, Sci_PositionU end, WordList &keyw
s[j] = styler[i]; s[j] = styler[i];
} }
s[j] = '\0'; s[j] = '\0';
int chAttr; int chAttr = SCE_RB_IDENTIFIER;
int style = SCE_RB_DEFAULT;
if (0 == strcmp(prevWord, "class")) if (0 == strcmp(prevWord, "class"))
chAttr = SCE_RB_CLASSNAME; chAttr = SCE_RB_CLASSNAME;
else if (0 == strcmp(prevWord, "module")) else if (0 == strcmp(prevWord, "module"))
chAttr = SCE_RB_MODULE_NAME; chAttr = SCE_RB_MODULE_NAME;
else if (0 == strcmp(prevWord, "def")) else if (0 == strcmp(prevWord, "def")) {
chAttr = SCE_RB_DEFNAME; chAttr = SCE_RB_DEFNAME;
if (ch == '.') {
if (strcmp(s, "self") == 0) {
style = SCE_RB_WORD_DEMOTED;
} else {
style = SCE_RB_IDENTIFIER;
}
}
}
else if (keywords.InList(s) && ((start == 0) || !followsDot(start - 1, styler))) { else if (keywords.InList(s) && ((start == 0) || !followsDot(start - 1, styler))) {
if (keywordIsAmbiguous(s) if (keywordIsAmbiguous(s)
&& keywordIsModifier(s, start, styler)) { && keywordIsModifier(s, start, styler)) {
@ -136,15 +145,15 @@ static int ClassifyWordRb(Sci_PositionU start, Sci_PositionU end, WordList &keyw
chAttr = SCE_RB_WORD_DEMOTED; chAttr = SCE_RB_WORD_DEMOTED;
} else { } else {
chAttr = SCE_RB_WORD; chAttr = SCE_RB_WORD;
} style = SCE_RB_WORD;
} else
chAttr = SCE_RB_IDENTIFIER;
styler.ColourTo(end, chAttr);
if (chAttr == SCE_RB_WORD) {
strcpy(prevWord, s); strcpy(prevWord, s);
} else { }
}
if (style == SCE_RB_DEFAULT) {
style = chAttr;
prevWord[0] = 0; prevWord[0] = 0;
} }
styler.ColourTo(end, style);
return chAttr; return chAttr;
} }
@ -461,7 +470,6 @@ static Sci_Position findExpressionStart(Sci_Position pos,
static bool sureThisIsNotHeredoc(Sci_Position lt2StartPos, static bool sureThisIsNotHeredoc(Sci_Position lt2StartPos,
Accessor &styler) { Accessor &styler) {
int prevStyle;
// Use full document, not just part we're styling // Use full document, not just part we're styling
Sci_Position lengthDoc = styler.Length(); Sci_Position lengthDoc = styler.Length();
Sci_Position lineStart = styler.GetLine(lt2StartPos); Sci_Position lineStart = styler.GetLine(lt2StartPos);
@ -478,9 +486,10 @@ static bool sureThisIsNotHeredoc(Sci_Position lt2StartPos,
if (firstWordPosn >= lt2StartPos) { if (firstWordPosn >= lt2StartPos) {
return definitely_not_a_here_doc; return definitely_not_a_here_doc;
} }
prevStyle = styler.StyleAt(firstWordPosn); int prevStyle = styler.StyleAt(firstWordPosn);
// If we have '<<' following a keyword, it's not a heredoc // If we have '<<' following a keyword, it's not a heredoc
if (prevStyle != SCE_RB_IDENTIFIER if (prevStyle != SCE_RB_IDENTIFIER
&& prevStyle != SCE_RB_GLOBAL // $stdout and $stderr
&& prevStyle != SCE_RB_SYMBOL && prevStyle != SCE_RB_SYMBOL
&& prevStyle != SCE_RB_INSTANCE_VAR && prevStyle != SCE_RB_INSTANCE_VAR
&& prevStyle != SCE_RB_CLASS_VAR) { && prevStyle != SCE_RB_CLASS_VAR) {
@ -595,7 +604,7 @@ static bool sureThisIsNotHeredoc(Sci_Position lt2StartPos,
return definitely_not_a_here_doc; return definitely_not_a_here_doc;
} else { } else {
char ch = styler[j]; char ch = styler[j];
if (ch == '#' || isEOLChar(ch)) { if (ch == '#' || isEOLChar(ch) || ch == '.' || ch == ',') {
// This is OK, so break and continue; // This is OK, so break and continue;
break; break;
} else { } else {
@ -714,6 +723,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
false); false);
bool preferRE = true; bool preferRE = true;
bool afterDef = false;
int state = initStyle; int state = initStyle;
Sci_Position lengthDoc = startPos + length; Sci_Position lengthDoc = startPos + length;
@ -791,7 +801,12 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
if (HereDoc.State == 1 && isEOLChar(ch)) { if (HereDoc.State == 1 && isEOLChar(ch)) {
// Begin of here-doc (the line after the here-doc delimiter): // Begin of here-doc (the line after the here-doc delimiter):
HereDoc.State = 2; HereDoc.State = 2;
styler.ColourTo(i-1, state); if (state == SCE_RB_WORD) {
const Sci_Position wordStartPos = styler.GetStartSegment();
ClassifyWordRb(wordStartPos, i - 1, ch, keywords, styler, prevWord);
} else {
styler.ColourTo(i - 1, state);
}
// Don't check for a missing quote, just jump into // Don't check for a missing quote, just jump into
// the here-doc state // the here-doc state
state = SCE_RB_HERE_Q; state = SCE_RB_HERE_Q;
@ -862,7 +877,10 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
Quote.New(); Quote.New();
Quote.Open(ch); Quote.Open(ch);
} else if (ch == '<' && chNext == '<' && chNext2 != '=') { } else if (ch == '<' && chNext == '<' && chNext2 != '=') {
if (afterDef) {
afterDef = false;
prevWord[0] = 0;
}
// Recognise the '<<' symbol - either a here document or a binary op // Recognise the '<<' symbol - either a here document or a binary op
styler.ColourTo(i - 1, state); styler.ColourTo(i - 1, state);
i++; i++;
@ -893,6 +911,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
} }
preferRE = (state != SCE_RB_HERE_DELIM); preferRE = (state != SCE_RB_HERE_DELIM);
} else if (ch == ':') { } else if (ch == ':') {
afterDef = false;
styler.ColourTo(i - 1, state); styler.ColourTo(i - 1, state);
if (chNext == ':') { if (chNext == ':') {
// Mark "::" as an operator, not symbol start // Mark "::" as an operator, not symbol start
@ -1009,7 +1028,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
state = SCE_RB_DEFAULT; state = SCE_RB_DEFAULT;
preferRE = true; preferRE = true;
} }
} else if (ch == '%') { } else if (ch == '%' && !afterDef) {
styler.ColourTo(i - 1, state); styler.ColourTo(i - 1, state);
bool have_string = false; bool have_string = false;
if (strchr(q_chars, chNext) && !isSafeWordcharOrHigh(chNext2)) { if (strchr(q_chars, chNext) && !isSafeWordcharOrHigh(chNext2)) {
@ -1046,6 +1065,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
preferRE = true; preferRE = true;
} }
} else if (ch == '?') { } else if (ch == '?') {
afterDef = false;
styler.ColourTo(i - 1, state); styler.ColourTo(i - 1, state);
if (iswhitespace(chNext) || chNext == '\n' || chNext == '\r') { if (iswhitespace(chNext) || chNext == '\n' || chNext == '\r') {
styler.ColourTo(i, SCE_RB_OPERATOR); styler.ColourTo(i, SCE_RB_OPERATOR);
@ -1057,6 +1077,16 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
} }
} else if (isoperator(ch) || ch == '.') { } else if (isoperator(ch) || ch == '.') {
styler.ColourTo(i - 1, state); styler.ColourTo(i - 1, state);
if (afterDef && ch != '.') {
afterDef = false;
prevWord[0] = 0;
if (chNext == '@' && (ch == '+' || ch == '-' || ch == '!')) {
// unary operator method
ch = chNext;
chNext = chNext2;
i += 1;
}
}
styler.ColourTo(i, SCE_RB_OPERATOR); styler.ColourTo(i, SCE_RB_OPERATOR);
// If we're ending an expression or block, // If we're ending an expression or block,
// assume it ends an object, and the ambivalent // assume it ends an object, and the ambivalent
@ -1082,6 +1112,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
} }
// Stay in default state // Stay in default state
} else if (isEOLChar(ch)) { } else if (isEOLChar(ch)) {
afterDef = false;
// Make sure it's a true line-end, with no backslash // Make sure it's a true line-end, with no backslash
if ((ch == '\r' || (ch == '\n' && chPrev != '\r')) if ((ch == '\r' || (ch == '\n' && chPrev != '\r'))
&& chPrev != '\\') { && chPrev != '\\') {
@ -1089,6 +1120,9 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
preferRE = true; preferRE = true;
} }
} }
if (afterDef && state != SCE_RB_DEFAULT) {
afterDef = false;
}
} else if (state == SCE_RB_WORD) { } else if (state == SCE_RB_WORD) {
if (ch == '.' || !isSafeWordcharOrHigh(ch)) { if (ch == '.' || !isSafeWordcharOrHigh(ch)) {
// Words include x? in all contexts, // Words include x? in all contexts,
@ -1127,9 +1161,10 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
preferRE = false; preferRE = false;
} else { } else {
Sci_Position wordStartPos = styler.GetStartSegment(); Sci_Position wordStartPos = styler.GetStartSegment();
int word_style = ClassifyWordRb(wordStartPos, i - 1, keywords, styler, prevWord); int word_style = ClassifyWordRb(wordStartPos, i - 1, ch, keywords, styler, prevWord);
switch (word_style) { switch (word_style) {
case SCE_RB_WORD: case SCE_RB_WORD:
afterDef = strcmp(prevWord, "def") == 0;
preferRE = RE_CanFollowKeyword(prevWord); preferRE = RE_CanFollowKeyword(prevWord);
break; break;
@ -1152,6 +1187,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
if (ch == '.') { if (ch == '.') {
// We might be redefining an operator-method // We might be redefining an operator-method
preferRE = false; preferRE = false;
afterDef = word_style == SCE_RB_DEFNAME;
} }
// And if it's the first // And if it's the first
redo_char(i, ch, chNext, chNext2, state); // pass by ref redo_char(i, ch, chNext, chNext2, state); // pass by ref
@ -1300,7 +1336,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
i - HereDoc.DelimiterLength + 1, i - HereDoc.DelimiterLength + 1,
lengthDoc, lengthDoc,
HereDoc.Delimiter)) { HereDoc.Delimiter)) {
styler.ColourTo(i - 1 - HereDoc.DelimiterLength, state); styler.ColourTo(i - HereDoc.DelimiterLength, state);
styler.ColourTo(i, SCE_RB_HERE_DELIM); styler.ColourTo(i, SCE_RB_HERE_DELIM);
state = SCE_RB_DEFAULT; state = SCE_RB_DEFAULT;
preferRE = false; preferRE = false;
@ -1459,7 +1495,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
if (state == SCE_RB_WORD) { if (state == SCE_RB_WORD) {
// We've ended on a word, possibly at EOF, and need to // We've ended on a word, possibly at EOF, and need to
// classify it. // classify it.
(void) ClassifyWordRb(styler.GetStartSegment(), lengthDoc - 1, keywords, styler, prevWord); (void) ClassifyWordRb(styler.GetStartSegment(), lengthDoc - 1, '\0', keywords, styler, prevWord);
} else { } else {
styler.ColourTo(lengthDoc - 1, state); styler.ColourTo(lengthDoc - 1, state);
} }
@ -1754,10 +1790,21 @@ static void FoldRbDoc(Sci_PositionU startPos, Sci_Position length, int initStyle
& SC_FOLDLEVELNUMBERMASK & SC_FOLDLEVELNUMBERMASK
& ~SC_FOLDLEVELBASE); & ~SC_FOLDLEVELBASE);
int levelCurrent = levelPrev; int levelCurrent = levelPrev;
char chPrev = '\0';
char chNext = styler[startPos]; char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos); int styleNext = styler.StyleAt(startPos);
int stylePrev = startPos <= 1 ? SCE_RB_DEFAULT : styler.StyleAt(startPos - 1); int stylePrev = startPos <= 1 ? SCE_RB_DEFAULT : styler.StyleAt(startPos - 1);
bool buffer_ends_with_eol = false; // detect endless method definition to fix up code folding
enum class MethodDefinition {
None,
Define,
Operator,
Name,
Argument,
};
MethodDefinition method_definition = MethodDefinition::None;
int argument_paren_count = 0;
for (Sci_PositionU i = startPos; i < endPos; i++) { for (Sci_PositionU i = startPos; i < endPos; i++) {
char ch = chNext; char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1); chNext = styler.SafeGetCharAt(i + 1);
@ -1800,8 +1847,10 @@ static void FoldRbDoc(Sci_PositionU startPos, Sci_Position length, int initStyle
// Don't decrement below 0 // Don't decrement below 0
if (levelCurrent > 0) if (levelCurrent > 0)
levelCurrent--; levelCurrent--;
} else if (!strcmp(prevWord, "def")) {
levelCurrent++;
method_definition = MethodDefinition::Define;
} else if (!strcmp(prevWord, "if") } else if (!strcmp(prevWord, "if")
|| !strcmp(prevWord, "def")
|| !strcmp(prevWord, "class") || !strcmp(prevWord, "class")
|| !strcmp(prevWord, "module") || !strcmp(prevWord, "module")
|| !strcmp(prevWord, "begin") || !strcmp(prevWord, "begin")
@ -1820,8 +1869,64 @@ static void FoldRbDoc(Sci_PositionU startPos, Sci_Position length, int initStyle
} else if (styleNext == SCE_RB_DEFAULT) { } else if (styleNext == SCE_RB_DEFAULT) {
levelCurrent--; levelCurrent--;
} }
} else if (style == SCE_RB_STRING_QW) {
if (stylePrev != style) {
levelCurrent++;
} else if (styleNext != style) {
levelCurrent--;
} }
if (atEOL) { }
if (method_definition != MethodDefinition::None) {
switch (method_definition) {
case MethodDefinition::Define:
if (style == SCE_RB_OPERATOR) {
method_definition = MethodDefinition::Operator;
} else if (style == SCE_RB_DEFNAME || style == SCE_RB_WORD_DEMOTED || style == SCE_RB_CLASSNAME || style == SCE_RB_IDENTIFIER) {
method_definition = MethodDefinition::Name;
} else if (!(style == SCE_RB_WORD || IsASpaceOrTab(ch))) {
method_definition = MethodDefinition::None;
}
if (method_definition <= MethodDefinition::Define) {
break;
}
// fall through for unary operator or single letter name
[[fallthrough]];
case MethodDefinition::Operator:
case MethodDefinition::Name:
if (isEOLChar(chNext) || chNext == '#') {
method_definition = MethodDefinition::None;
} else if (chNext == '(' || chNext <= ' ') {
// setter method cannot be defined in an endless method definition.
if (ch == '=' && (method_definition == MethodDefinition::Name || chPrev == ']')) {
method_definition = MethodDefinition::None;
} else {
method_definition = MethodDefinition::Argument;
argument_paren_count = 0;
}
}
break;
case MethodDefinition::Argument:
if (style == SCE_RB_OPERATOR) {
if (ch == '(') {
++argument_paren_count;
} else if (ch == ')') {
--argument_paren_count;
} else if (argument_paren_count == 0) {
method_definition = MethodDefinition::None;
if (ch == '=' && levelCurrent > 0) {
levelCurrent--;
}
}
} else if (argument_paren_count == 0 && !IsASpaceOrTab(ch)) {
// '=' must be first character after method name or right parenthesis
method_definition = MethodDefinition::None;
}
break;
default:
break;
}
}
if (atEOL || (i == endPos - 1)) {
int lev = levelPrev; int lev = levelPrev;
if (visibleChars == 0 && foldCompact) if (visibleChars == 0 && foldCompact)
lev |= SC_FOLDLEVELWHITEFLAG; lev |= SC_FOLDLEVELWHITEFLAG;
@ -1831,23 +1936,14 @@ static void FoldRbDoc(Sci_PositionU startPos, Sci_Position length, int initStyle
lineCurrent++; lineCurrent++;
levelPrev = levelCurrent; levelPrev = levelCurrent;
visibleChars = 0; visibleChars = 0;
buffer_ends_with_eol = true; method_definition = MethodDefinition::None;
argument_paren_count = 0;
} else if (!isspacechar(ch)) { } else if (!isspacechar(ch)) {
visibleChars++; visibleChars++;
buffer_ends_with_eol = false;
} }
chPrev = ch;
stylePrev = style; stylePrev = style;
} }
// Fill in the real level of the next line, keeping the current flags as they will be filled in later
if (!buffer_ends_with_eol) {
int new_lev = levelCurrent;
if (visibleChars == 0 && foldCompact)
new_lev |= SC_FOLDLEVELWHITEFLAG;
if ((levelCurrent > levelPrev) && (visibleChars > 0))
new_lev |= SC_FOLDLEVELHEADERFLAG;
levelCurrent = new_lev;
}
styler.SetLevel(lineCurrent, levelCurrent|SC_FOLDLEVELBASE);
} }
static const char *const rubyWordListDesc[] = { static const char *const rubyWordListDesc[] = {

View File

@ -122,12 +122,12 @@ public:
} }
// Return style value from buffer when in buffer, else retrieve from document. // Return style value from buffer when in buffer, else retrieve from document.
// This is faster and can avoid calls to Flush() as that may be expensive. // This is faster and can avoid calls to Flush() as that may be expensive.
char BufferStyleAt(Sci_Position position) const { int BufferStyleAt(Sci_Position position) const {
const Sci_Position index = position - startPosStyling; const Sci_Position index = position - startPosStyling;
if (index >= 0 && index < validLen) { if (index >= 0 && index < validLen) {
return styleBuf[index]; return static_cast<unsigned char>(styleBuf[index]);
} }
return pAccess->StyleAt(position); return static_cast<unsigned char>(pAccess->StyleAt(position));
} }
Sci_Position GetLine(Sci_Position position) const { Sci_Position GetLine(Sci_Position position) const {
return pAccess->LineFromPosition(position); return pAccess->LineFromPosition(position);

View File

@ -6,6 +6,7 @@
// This file is in the public domain. // This file is in the public domain.
#include <cstdlib> #include <cstdlib>
#include <cstdint>
#include <cassert> #include <cassert>
#include <string> #include <string>
@ -20,6 +21,33 @@
using namespace Lexilla; using namespace Lexilla;
StyleContext::StyleContext(Sci_PositionU startPos, Sci_PositionU length,
int initStyle, LexAccessor &styler_, char chMask) :
styler(styler_),
multiByteAccess((styler.Encoding() == EncodingType::eightBit) ? nullptr : styler.MultiByteAccess()),
lengthDocument(static_cast<Sci_PositionU>(styler.Length())),
endPos(((startPos + length) < lengthDocument) ? (startPos + length) : (lengthDocument+1)),
lineDocEnd(styler.GetLine(lengthDocument)),
currentPosLastRelative(SIZE_MAX),
currentPos(startPos),
currentLine(styler.GetLine(startPos)),
lineEnd(styler.LineEnd(currentLine)),
lineStartNext(styler.LineStart(currentLine + 1)),
atLineStart(static_cast<Sci_PositionU>(styler.LineStart(currentLine)) == startPos),
// Mask off all bits which aren't in the chMask.
state(initStyle &chMask) {
styler.StartAt(startPos /*, chMask*/);
styler.StartSegment(startPos);
// Variable width is now 0 so GetNextChar gets the char at currentPos into chNext/widthNext
GetNextChar();
ch = chNext;
width = widthNext;
GetNextChar();
}
bool StyleContext::MatchIgnoreCase(const char *s) { bool StyleContext::MatchIgnoreCase(const char *s) {
if (MakeLowerCase(ch) != static_cast<unsigned char>(*s)) if (MakeLowerCase(ch) != static_cast<unsigned char>(*s))
return false; return false;
@ -54,19 +82,6 @@ bool StyleContext::MatchIgnoreCase2(const char *s) {
return true; return true;
} }
static void getRange(Sci_PositionU start,
Sci_PositionU end,
LexAccessor &styler,
char *s,
Sci_PositionU len) {
Sci_PositionU i = 0;
while ((i < end - start + 1) && (i < len-1)) {
s[i] = styler[start + i];
i++;
}
s[i] = '\0';
}
void StyleContext::GetCurrent(char *s, Sci_PositionU len) { void StyleContext::GetCurrent(char *s, Sci_PositionU len) {
styler.GetRange(styler.GetStartSegment(), currentPos, s, len); styler.GetRange(styler.GetStartSegment(), currentPos, s, len);
} }

View File

@ -16,21 +16,21 @@ namespace Lexilla {
// syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80 // syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80
class StyleContext { class StyleContext {
LexAccessor &styler; LexAccessor &styler;
Scintilla::IDocument *multiByteAccess; Scintilla::IDocument * const multiByteAccess;
Sci_PositionU endPos; const Sci_PositionU lengthDocument;
Sci_PositionU lengthDocument; const Sci_PositionU endPos;
const Sci_Position lineDocEnd;
// Used for optimizing GetRelativeCharacter // Used for optimizing GetRelativeCharacter
Sci_PositionU posRelative; Sci_PositionU posRelative = 0;
Sci_PositionU currentPosLastRelative; Sci_PositionU currentPosLastRelative;
Sci_Position offsetRelative; Sci_Position offsetRelative = 0;
void GetNextChar() { void GetNextChar() {
if (multiByteAccess) { if (multiByteAccess) {
chNext = multiByteAccess->GetCharacterAndWidth(currentPos+width, &widthNext); chNext = multiByteAccess->GetCharacterAndWidth(currentPos+width, &widthNext);
} else { } else {
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+width, 0)); chNext = static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+width, 0));
widthNext = 1;
} }
// End of line determined from line end position, allowing CR, LF, // End of line determined from line end position, allowing CR, LF,
// CRLF and Unicode line ends as set by document. // CRLF and Unicode line ends as set by document.
@ -43,59 +43,19 @@ class StyleContext {
public: public:
Sci_PositionU currentPos; Sci_PositionU currentPos;
Sci_Position currentLine; Sci_Position currentLine;
Sci_Position lineDocEnd;
Sci_Position lineEnd; Sci_Position lineEnd;
Sci_Position lineStartNext; Sci_Position lineStartNext;
bool atLineStart; bool atLineStart;
bool atLineEnd; bool atLineEnd = false;
int state; int state;
int chPrev; int chPrev = 0;
int ch; int ch = 0;
Sci_Position width; Sci_Position width = 0;
int chNext; int chNext = 0;
Sci_Position widthNext; Sci_Position widthNext = 1;
StyleContext(Sci_PositionU startPos, Sci_PositionU length, StyleContext(Sci_PositionU startPos, Sci_PositionU length,
int initStyle, LexAccessor &styler_, char chMask='\377') : int initStyle, LexAccessor &styler_, char chMask = '\377');
styler(styler_),
multiByteAccess(nullptr),
endPos(startPos + length),
posRelative(0),
currentPosLastRelative(0x7FFFFFFF),
offsetRelative(0),
currentPos(startPos),
currentLine(-1),
lineEnd(-1),
lineStartNext(-1),
atLineEnd(false),
state(initStyle & chMask), // Mask off all bits which aren't in the chMask.
chPrev(0),
ch(0),
width(0),
chNext(0),
widthNext(1) {
if (styler.Encoding() != EncodingType::eightBit) {
multiByteAccess = styler.MultiByteAccess();
}
styler.StartAt(startPos /*, chMask*/);
styler.StartSegment(startPos);
currentLine = styler.GetLine(startPos);
lineEnd = styler.LineEnd(currentLine);
lineStartNext = styler.LineStart(currentLine+1);
lengthDocument = static_cast<Sci_PositionU>(styler.Length());
if (endPos == lengthDocument)
endPos++;
lineDocEnd = styler.GetLine(lengthDocument);
atLineStart = static_cast<Sci_PositionU>(styler.LineStart(currentLine)) == startPos;
// Variable width is now 0 so GetNextChar gets the char at currentPos into chNext/widthNext
width = 0;
GetNextChar();
ch = chNext;
width = widthNext;
GetNextChar();
}
// Deleted so StyleContext objects can not be copied. // Deleted so StyleContext objects can not be copied.
StyleContext(const StyleContext &) = delete; StyleContext(const StyleContext &) = delete;
StyleContext &operator=(const StyleContext &) = delete; StyleContext &operator=(const StyleContext &) = delete;

View File

@ -26,6 +26,7 @@
// C++ wrappers of C standard library // C++ wrappers of C standard library
#include <cstdlib> #include <cstdlib>
#include <cstdint>
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <cctype> #include <cctype>

View File

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

View File

@ -1,7 +1,12 @@
# Test lexers # Test lexers
# build lexilla.so and TestLexers then run TestLexers # build lexilla.so and TestLexers then run TestLexers
JOBS="--jobs=$(getconf _NPROCESSORS_ONLN)"
(
cd ../src cd ../src
make DEBUG=1 make "$JOBS" DEBUG=1
)
(
cd ../test cd ../test
make DEBUG=1 make DEBUG=1
make test make test
)

View File

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

View File

@ -851,7 +851,7 @@
buildSettings = { buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5.1.5; CURRENT_PROJECT_VERSION = 5.1.6;
DEVELOPMENT_TEAM = 4F446KW87E; DEVELOPMENT_TEAM = 4F446KW87E;
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1; DYLIB_CURRENT_VERSION = 1;
@ -877,7 +877,7 @@
buildSettings = { buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5.1.5; CURRENT_PROJECT_VERSION = 5.1.6;
DEVELOPMENT_TEAM = 4F446KW87E; DEVELOPMENT_TEAM = 4F446KW87E;
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1; DYLIB_CURRENT_VERSION = 1;

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -4,8 +4,8 @@
#include <windows.h> #include <windows.h>
#define VERSION_LEXILLA "5.1.5" #define VERSION_LEXILLA "5.1.6"
#define VERSION_WORDS 5, 1, 5, 0 #define VERSION_WORDS 5, 1, 6, 0
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_WORDS FILEVERSION VERSION_WORDS

View File

@ -100,8 +100,14 @@ Other settings are treated as lexer or folder properties and forwarded to the le
It is often necessary to set 'fold' in SciTE.properties to cause folding. It is often necessary to set 'fold' in SciTE.properties to cause folding.
If there is a need to test additional configurations of keywords or properties then Properties can be set for a particular file with an "if $(=" or "match" expression like so:
create another subdirectory with the different settings in a new SciTE.properties. if $(= $(FileNameExt);HeaderEOLFill_1.md)
lexer.markdown.header.eolfill=1
match Header*1.md
lexer.markdown.header.eolfill=1
More complex tests with additional configurations of keywords or properties can be performed
by creating another subdirectory with the different settings in a new SciTE.properties.
There is some support for running benchmarks on lexers and folders. The properties There is some support for running benchmarks on lexers and folders. The properties
testlexers.repeat.lex and testlexers.repeat.fold specify the number of times example testlexers.repeat.lex and testlexers.repeat.fold specify the number of times example

View File

@ -40,6 +40,7 @@ namespace {
}; };
int UnicodeFromUTF8(const unsigned char *us) noexcept { int UnicodeFromUTF8(const unsigned char *us) noexcept {
assert(us);
switch (UTF8BytesOfLead[us[0]]) { switch (UTF8BytesOfLead[us[0]]) {
case 1: case 1:
return us[0]; return us[0];
@ -56,6 +57,56 @@ namespace {
return (ch >= 0x80) && (ch < 0xc0); return (ch >= 0x80) && (ch < 0xc0);
} }
constexpr unsigned char TrailByteValue(unsigned char c) {
// The top 2 bits are 0b10 to indicate a trail byte.
// The lower 6 bits contain the value.
return c & 0b0011'1111;
}
}
std::u32string UTF32FromUTF8(std::string_view svu8) {
std::u32string ret;
for (size_t i = 0; i < svu8.length();) {
unsigned char ch = svu8.at(i);
const unsigned int byteCount = UTF8BytesOfLead[ch];
unsigned int value = 0;
if (i + byteCount > svu8.length()) {
// Trying to read past end
ret.push_back(ch);
break;
}
i++;
switch (byteCount) {
case 1:
value = ch;
break;
case 2:
value = (ch & 0x1F) << 6;
ch = svu8.at(i++);
value += TrailByteValue(ch);
break;
case 3:
value = (ch & 0xF) << 12;
ch = svu8.at(i++);
value += TrailByteValue(ch) << 6;
ch = svu8.at(i++);
value += TrailByteValue(ch);
break;
default:
value = (ch & 0x7) << 18;
ch = svu8.at(i++);
value += TrailByteValue(ch) << 12;
ch = svu8.at(i++);
value += TrailByteValue(ch) << 6;
ch = svu8.at(i++);
value += TrailByteValue(ch);
break;
}
ret.push_back(value);
}
return ret;
} }
void TestDocument::Set(std::string_view sv) { void TestDocument::Set(std::string_view sv) {
@ -65,7 +116,7 @@ void TestDocument::Set(std::string_view sv) {
endStyled = 0; endStyled = 0;
lineStarts.push_back(0); lineStarts.push_back(0);
for (size_t pos = 0; pos < text.length(); pos++) { for (size_t pos = 0; pos < text.length(); pos++) {
if (text[pos] == '\n') { if (text.at(pos) == '\n') {
lineStarts.push_back(pos + 1); lineStarts.push_back(pos + 1);
} }
} }
@ -145,15 +196,16 @@ void SCI_METHOD TestDocument::StartStyling(Sci_Position position) {
bool SCI_METHOD TestDocument::SetStyleFor(Sci_Position length, char style) { bool SCI_METHOD TestDocument::SetStyleFor(Sci_Position length, char style) {
for (Sci_Position i = 0; i < length; i++) { for (Sci_Position i = 0; i < length; i++) {
textStyles[endStyled] = style; textStyles.at(endStyled) = style;
endStyled++; endStyled++;
} }
return true; return true;
} }
bool SCI_METHOD TestDocument::SetStyles(Sci_Position length, const char *styles) { bool SCI_METHOD TestDocument::SetStyles(Sci_Position length, const char *styles) {
assert(styles);
for (Sci_Position i = 0; i < length; i++) { for (Sci_Position i = 0; i < length; i++) {
textStyles[endStyled] = styles[i]; textStyles.at(endStyled) = styles[i];
endStyled++; endStyled++;
} }
return true; return true;
@ -252,8 +304,9 @@ int SCI_METHOD TestDocument::GetCharacterAndWidth(Sci_Position position, Sci_Pos
} }
const int widthCharBytes = UTF8BytesOfLead[leadByte]; const int widthCharBytes = UTF8BytesOfLead[leadByte];
unsigned char charBytes[] = { leadByte,0,0,0 }; unsigned char charBytes[] = { leadByte,0,0,0 };
for (int b = 1; b < widthCharBytes; b++) for (int b = 1; b < widthCharBytes; b++) {
charBytes[b] = text[position + b]; charBytes[b] = text.at(position + b);
}
if (pWidth) { if (pWidth) {
*pWidth = widthCharBytes; *pWidth = widthCharBytes;

View File

@ -8,6 +8,8 @@
#ifndef TESTDOCUMENT_H #ifndef TESTDOCUMENT_H
#define TESTDOCUMENT_H #define TESTDOCUMENT_H
std::u32string UTF32FromUTF8(std::string_view svu8);
class TestDocument : public Scintilla::IDocument { class TestDocument : public Scintilla::IDocument {
std::string text; std::string text;
std::string textStyles; std::string textStyles;

View File

@ -29,9 +29,233 @@
namespace { namespace {
constexpr char MakeLowerCase(char c) noexcept {
if (c >= 'A' && c <= 'Z') {
return c - 'A' + 'a';
} else {
return c;
}
}
[[maybe_unused]] void LowerCaseAZ(std::string &s) {
std::transform(s.begin(), s.end(), s.begin(), MakeLowerCase);
}
int IntFromString(std::u32string_view s) noexcept {
if (s.empty()) {
return 0;
}
const bool negate = s.front() == '-';
if (negate) {
s.remove_prefix(1);
}
int value = 0;
while (!s.empty()) {
value = value * 10 + s.front() - '0';
s.remove_prefix(1);
}
return negate ? -value : value;
}
bool PatternMatch(std::u32string_view pattern, std::u32string_view text) noexcept {
if (pattern == text) {
return true;
} else if (pattern.empty()) {
return false;
} else if (pattern.front() == '\\') {
pattern.remove_prefix(1);
if (pattern.empty()) {
// Escape with nothing being escaped
return false;
}
if (text.empty()) {
return false;
}
if (pattern.front() == text.front()) {
pattern.remove_prefix(1);
text.remove_prefix(1);
return PatternMatch(pattern, text);
}
return false;
} else if (pattern.front() == '*') {
pattern.remove_prefix(1);
if (!pattern.empty() && pattern.front() == '*') {
pattern.remove_prefix(1);
// "**" matches anything including "/"
while (!text.empty()) {
if (PatternMatch(pattern, text)) {
return true;
}
text.remove_prefix(1);
}
} else {
while (!text.empty()) {
if (PatternMatch(pattern, text)) {
return true;
}
if (text.front() == '/') {
// "/" not matched by single "*"
return false;
}
text.remove_prefix(1);
}
}
assert(text.empty());
// Consumed whole text with wildcard so match if pattern consumed
return pattern.empty();
} else if (text.empty()) {
return false;
} else if (pattern.front() == '?') {
if (text.front() == '/') {
return false;
}
pattern.remove_prefix(1);
text.remove_prefix(1);
return PatternMatch(pattern, text);
} else if (pattern.front() == '[') {
pattern.remove_prefix(1);
if (pattern.empty()) {
return false;
}
const bool positive = pattern.front() != '!';
if (!positive) {
pattern.remove_prefix(1);
if (pattern.empty()) {
return false;
}
}
bool inSet = false;
if (!pattern.empty() && pattern.front() == ']') {
// First is allowed to be ']'
if (pattern.front() == text.front()) {
inSet = true;
}
pattern.remove_prefix(1);
}
char32_t start = 0;
while (!pattern.empty() && pattern.front() != ']') {
if (pattern.front() == '-') {
pattern.remove_prefix(1);
if (!pattern.empty()) {
const char32_t end = pattern.front();
if ((text.front() >= start) && (text.front() <= end)) {
inSet = true;
}
}
} else if (pattern.front() == text.front()) {
inSet = true;
}
if (!pattern.empty()) {
start = pattern.front();
pattern.remove_prefix(1);
}
}
if (!pattern.empty()) {
pattern.remove_prefix(1);
}
if (inSet != positive) {
return false;
}
text.remove_prefix(1);
return PatternMatch(pattern, text);
} else if (pattern.front() == '{') {
if (pattern.length() < 2) {
return false;
}
const size_t endParen = pattern.find('}');
if (endParen == std::u32string_view::npos) {
// Malformed {x} pattern
return false;
}
std::u32string_view parenExpression = pattern.substr(1, endParen - 1);
bool inSet = false;
const size_t dotdot = parenExpression.find(U"..");
if (dotdot != std::u32string_view::npos) {
// Numeric range: {10..20}
const std::u32string_view firstRange = parenExpression.substr(0, dotdot);
const std::u32string_view lastRange = parenExpression.substr(dotdot+2);
if (firstRange.empty() || lastRange.empty()) {
// Malformed {s..e} range pattern
return false;
}
const size_t endInteger = text.find_last_of(U"-0123456789");
if (endInteger == std::u32string_view::npos) {
// No integer in text
return false;
}
const std::u32string_view intPart = text.substr(0, endInteger+1);
const int first = IntFromString(firstRange);
const int last = IntFromString(lastRange);
const int value = IntFromString(intPart);
if ((value >= first) && (value <= last)) {
inSet = true;
text.remove_prefix(intPart.length());
}
} else {
// Alternates: {a,b,cd}
size_t comma = parenExpression.find(',');
for (;;) {
const bool finalAlt = comma == std::u32string_view::npos;
const std::u32string_view oneAlt = finalAlt ? parenExpression :
parenExpression.substr(0, comma);
if (oneAlt == text.substr(0, oneAlt.length())) {
// match
inSet = true;
text.remove_prefix(oneAlt.length());
break;
}
if (finalAlt) {
break;
}
parenExpression.remove_prefix(oneAlt.length() + 1);
comma = parenExpression.find(',');
}
}
if (!inSet) {
return false;
}
pattern.remove_prefix(endParen + 1);
return PatternMatch(pattern, text);
} else if (pattern.front() == text.front()) {
pattern.remove_prefix(1);
text.remove_prefix(1);
return PatternMatch(pattern, text);
}
return false;
}
bool PathMatch(std::string pattern, std::string relPath) {
#if defined(_WIN32)
// Convert Windows path separators to Unix
std::replace(relPath.begin(), relPath.end(), '\\', '/');
#endif
#if defined(_WIN32) || defined(__APPLE__)
// Case-insensitive, only does ASCII but fine for test example files
LowerCaseAZ(pattern);
LowerCaseAZ(relPath);
#endif
const std::u32string patternU32 = UTF32FromUTF8(pattern);
const std::u32string relPathU32 = UTF32FromUTF8(relPath);
if (PatternMatch(patternU32, relPathU32)) {
return true;
}
const size_t lastSlash = relPathU32.rfind('/');
if (lastSlash == std::string::npos) {
return false;
}
// Match against just filename
const std::u32string fileNameU32 = relPathU32.substr(lastSlash+1);
return PatternMatch(patternU32, fileNameU32);
}
constexpr std::string_view suffixStyled = ".styled"; constexpr std::string_view suffixStyled = ".styled";
constexpr std::string_view suffixFolded = ".folded"; constexpr std::string_view suffixFolded = ".folded";
constexpr std::string_view prefixIf = "if ";
constexpr std::string_view prefixMatch = "match ";
constexpr std::string_view prefixEqual = "= ";
constexpr std::string_view prefixComment = "#";
std::string ReadFile(std::filesystem::path path) { std::string ReadFile(std::filesystem::path path) {
std::ifstream ifs(path, std::ios::binary); std::ifstream ifs(path, std::ios::binary);
std::string content((std::istreambuf_iterator<char>(ifs)), std::string content((std::istreambuf_iterator<char>(ifs)),
@ -40,6 +264,7 @@ std::string ReadFile(std::filesystem::path path) {
} }
std::string MarkedDocument(const Scintilla::IDocument *pdoc) { std::string MarkedDocument(const Scintilla::IDocument *pdoc) {
assert(pdoc);
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
char prevStyle = -1; char prevStyle = -1;
for (Sci_Position pos = 0; pos < pdoc->Length(); pos++) { for (Sci_Position pos = 0; pos < pdoc->Length(); pos++) {
@ -71,6 +296,7 @@ void PrintLevel(std::ostringstream &os, int level) {
} }
std::string FoldedDocument(const Scintilla::IDocument *pdoc) { std::string FoldedDocument(const Scintilla::IDocument *pdoc) {
assert(pdoc);
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
Sci_Position linePrev = -1; Sci_Position linePrev = -1;
char ch = '\0'; char ch = '\0';
@ -94,12 +320,115 @@ std::pair<std::string, std::string> MarkedAndFoldedDocument(const Scintilla::IDo
return { MarkedDocument(pdoc), FoldedDocument(pdoc) }; return { MarkedDocument(pdoc), FoldedDocument(pdoc) };
} }
std::vector<std::string> StringSplit(const std::string_view &text, int separator) {
std::vector<std::string> vs(text.empty() ? 0 : 1);
for (std::string_view::const_iterator it = text.begin(); it != text.end(); ++it) {
if (*it == separator) {
vs.push_back(std::string());
} else {
vs.back() += *it;
}
}
return vs;
}
static constexpr bool IsSpaceOrTab(char ch) noexcept {
return (ch == ' ') || (ch == '\t');
}
class PropertyMap { class PropertyMap {
std::string Evaluate(std::string_view text) {
if (text.find(' ') != std::string_view::npos) {
if (text.starts_with(prefixEqual)) {
const std::string_view sExpressions = text.substr(prefixEqual.length());
std::vector<std::string> parts = StringSplit(sExpressions, ';');
if (parts.size() > 1) {
for (size_t part = 1; part < parts.size(); part++) {
if (parts.at(part) != parts.at(0)) {
return "0";
}
}
return "1";
}
}
return {};
} else {
std::optional<std::string> value = GetProperty(text);
if (value) {
return *value;
}
return {};
}
}
std::string Expand(std::string withVars) {
constexpr size_t maxVars = 100;
size_t varStart = withVars.rfind("$(");
for (size_t count = 0; (count < maxVars) && (varStart != std::string::npos); count++) {
const size_t varEnd = withVars.find(')', varStart + 2);
if (varEnd == std::string::npos) {
break;
}
const std::string_view whole = withVars;
const std::string_view var = whole.substr(varStart + 2, varEnd - (varStart + 2));
const std::string val = Evaluate(var);
withVars.erase(varStart, varEnd - varStart + 1);
withVars.insert(varStart, val);
varStart = withVars.rfind("$(");
}
return withVars;
}
bool ProcessLine(std::string_view text, bool ifIsTrue) {
// If clause ends with first non-indented line
if (!ifIsTrue && (text.empty() || IsSpaceOrTab(text.at(0)))) {
return false;
}
ifIsTrue = true;
if (text.starts_with(prefixIf)) {
const std::string value = Expand(std::string(text.substr(prefixIf.length())));
if (value == "0" || value == "") {
ifIsTrue = false;
}
} else if (text.starts_with(prefixMatch)) {
std::optional<std::string> fileNameExt = GetProperty("FileNameExt");
if (fileNameExt) {
std::string pattern(text.substr(prefixMatch.length()));
// Remove trailing white space
while (!pattern.empty() && IsSpaceOrTab(pattern.back())) {
pattern.pop_back();
}
ifIsTrue = PathMatch(pattern, *fileNameExt);
} else {
ifIsTrue = false;
}
} else {
while (!text.empty() && IsSpaceOrTab(text.at(0))) {
text.remove_prefix(1);
}
if (text.starts_with(prefixComment)) {
return ifIsTrue;
}
const size_t positionEquals = text.find("=");
if (positionEquals != std::string::npos) {
const std::string key(text.substr(0, positionEquals));
const std::string_view value = text.substr(positionEquals + 1);
properties[key] = value;
}
}
return ifIsTrue;
}
public: public:
using PropMap = std::map<std::string, std::string>; using PropMap = std::map<std::string, std::string>;
PropMap properties; PropMap properties;
void ReadFromFile(std::filesystem::path path) { void ReadFromFile(std::filesystem::path path) {
bool ifIsTrue = true;
std::ifstream ifs(path); std::ifstream ifs(path);
std::string line; std::string line;
std::string logicalLine; std::string logicalLine;
@ -112,12 +441,7 @@ public:
if (logicalLine.ends_with("\\")) { if (logicalLine.ends_with("\\")) {
logicalLine.pop_back(); logicalLine.pop_back();
} else { } else {
const size_t positionEquals = logicalLine.find("="); ifIsTrue = ProcessLine(logicalLine, ifIsTrue);
if (positionEquals != std::string::npos) {
const std::string key = logicalLine.substr(0, positionEquals);
const std::string value = logicalLine.substr(positionEquals + 1);
properties[key] = value;
}
logicalLine.clear(); logicalLine.clear();
} }
} }
@ -171,7 +495,8 @@ bool CheckSame(std::string_view augmentedText, std::string_view augmentedTextNew
} }
const size_t lineNumber = FirstLineDifferent(augmentedText, augmentedTextNew) + 1; const size_t lineNumber = FirstLineDifferent(augmentedText, augmentedTextNew) + 1;
std::cout << "\n" << path.string() << ":" << lineNumber << ":"; std::cout << "\n" << path.string() << ":" << lineNumber << ":";
std::cout << " has different " << item << "\n\n"; const std::string differenceType = augmentedText.empty() ? "new" : "different";
std::cout << " has " << differenceType << " " << item << "\n\n";
std::filesystem::path pathNew = path; std::filesystem::path pathNew = path;
pathNew += suffix; pathNew += suffix;
pathNew += ".new"; pathNew += ".new";
@ -204,6 +529,7 @@ int UnixToWindows(std::string &s) {
const std::string BOM = "\xEF\xBB\xBF"; const std::string BOM = "\xEF\xBB\xBF";
void StyleLineByLine(TestDocument &doc, Scintilla::ILexer5 *plex) { void StyleLineByLine(TestDocument &doc, Scintilla::ILexer5 *plex) {
assert(plex);
Scintilla::IDocument *pdoc = &doc; Scintilla::IDocument *pdoc = &doc;
const Sci_Position lines = doc.LineFromPosition(doc.Length()); const Sci_Position lines = doc.LineFromPosition(doc.Length());
Sci_Position startLine = 0; Sci_Position startLine = 0;
@ -218,7 +544,8 @@ void StyleLineByLine(TestDocument &doc, Scintilla::ILexer5 *plex) {
} }
} }
void TestCRLF(std::filesystem::path path, const std::string s, Scintilla::ILexer5 *plex, bool disablePerLineTests) { bool TestCRLF(std::filesystem::path path, const std::string s, Scintilla::ILexer5 *plex, bool disablePerLineTests) {
bool success = true;
// Convert all line ends to \r\n to check if styles change between \r and \n which makes // Convert all line ends to \r\n to check if styles change between \r and \n which makes
// it difficult to test on different platforms when files may have line ends changed. // it difficult to test on different platforms when files may have line ends changed.
std::string text = s; std::string text = s;
@ -244,6 +571,7 @@ void TestCRLF(std::filesystem::path path, const std::string s, Scintilla::ILexer
std::cout << path.string() << ":" << line << ":" << std::cout << path.string() << ":" << line << ":" <<
" different styles between \\r and \\n at " << " different styles between \\r and \\n at " <<
pos << ": " << prevStyle << ", " << styleNow << "\n"; pos << ": " << prevStyle << ", " << styleNow << "\n";
success = false;
} }
line++; line++;
} }
@ -265,9 +593,11 @@ void TestCRLF(std::filesystem::path path, const std::string s, Scintilla::ILexer
if (styledText != styledTextUnix) { if (styledText != styledTextUnix) {
std::cout << "\n" << path.string() << ":1: has different styles with \\n versus \\r\\n line ends\n\n"; std::cout << "\n" << path.string() << ":1: has different styles with \\n versus \\r\\n line ends\n\n";
success = false;
} }
if (foldedText != foldedTextUnix) { if (foldedText != foldedTextUnix) {
std::cout << "\n" << path.string() << ":1: has different folds with \\n versus \\r\\n line ends\n\n"; std::cout << "\n" << path.string() << ":1: has different folds with \\n versus \\r\\n line ends\n\n";
success = false;
} }
// Test line by line lexing/folding with Unix \n line ends // Test line by line lexing/folding with Unix \n line ends
@ -277,14 +607,21 @@ void TestCRLF(std::filesystem::path path, const std::string s, Scintilla::ILexer
// Convert results from \n to \r\n run // Convert results from \n to \r\n run
UnixToWindows(styledTextNewPerLine); UnixToWindows(styledTextNewPerLine);
UnixToWindows(foldedTextNewPerLine); UnixToWindows(foldedTextNewPerLine);
CheckSame(styledTextUnix, styledTextNewPerLine, "per-line styles \\n", suffixStyled, path); if (!CheckSame(styledTextUnix, styledTextNewPerLine, "per-line styles \\n", suffixStyled, path)) {
CheckSame(foldedTextUnix, foldedTextNewPerLine, "per-line folds \\n", suffixFolded, path); success = false;
}
if (!CheckSame(foldedTextUnix, foldedTextNewPerLine, "per-line folds \\n", suffixFolded, path)) {
success = false;
}
} }
plex->Release(); plex->Release();
return success;
} }
void TestILexer(Scintilla::ILexer5 *plex) { void TestILexer(Scintilla::ILexer5 *plex) {
assert(plex);
// Test each method of the ILexer interface. // Test each method of the ILexer interface.
// Mostly ensures there are no crashes when calling methods. // Mostly ensures there are no crashes when calling methods.
// Some methods are tested later (Release, Lex, Fold). // Some methods are tested later (Release, Lex, Fold).
@ -320,11 +657,11 @@ void TestILexer(Scintilla::ILexer5 *plex) {
[[maybe_unused]] const int lineEndTypes = plex->LineEndTypesSupported(); [[maybe_unused]] const int lineEndTypes = plex->LineEndTypesSupported();
assert(lineEndTypes == 0 || lineEndTypes == 1); assert(lineEndTypes == 0 || lineEndTypes == 1);
if (const char *bases = plex->GetSubStyleBases()) { if (std::string_view bases = plex->GetSubStyleBases(); !bases.empty()) {
// Allocate a substyle for each possible style // Allocate a substyle for each possible style
while (*bases) { while (!bases.empty()) {
constexpr int newStyles = 3; constexpr int newStyles = 3;
const int base = *bases; const int base = bases.front();
const int baseStyle = plex->AllocateSubStyles(base, newStyles); const int baseStyle = plex->AllocateSubStyles(base, newStyles);
[[maybe_unused]] const int styleBack = plex->StyleFromSubStyle(baseStyle); [[maybe_unused]] const int styleBack = plex->StyleFromSubStyle(baseStyle);
assert(styleBack == base); assert(styleBack == base);
@ -333,7 +670,7 @@ void TestILexer(Scintilla::ILexer5 *plex) {
assert(start == baseStyle); assert(start == baseStyle);
[[maybe_unused]] const int len = plex->SubStylesLength(base); [[maybe_unused]] const int len = plex->SubStylesLength(base);
assert(len == newStyles); assert(len == newStyles);
bases++; bases.remove_prefix(1);
} }
plex->FreeSubStyles(); plex->FreeSubStyles();
} }
@ -359,6 +696,8 @@ void TestILexer(Scintilla::ILexer5 *plex) {
} }
void SetProperties(Scintilla::ILexer5 *plex, const PropertyMap &propertyMap, std::string_view fileName) { void SetProperties(Scintilla::ILexer5 *plex, const PropertyMap &propertyMap, std::string_view fileName) {
assert(plex);
// Set keywords, keywords2, ... keywords9, for this file // Set keywords, keywords2, ... keywords9, for this file
for (int kw = 0; kw < 10; kw++) { for (int kw = 0; kw < 10; kw++) {
std::string kwChoice("keywords"); std::string kwChoice("keywords");
@ -374,9 +713,7 @@ void SetProperties(Scintilla::ILexer5 *plex, const PropertyMap &propertyMap, std
// Set parameters of lexer // Set parameters of lexer
for (auto const &[key, val] : propertyMap.properties) { for (auto const &[key, val] : propertyMap.properties) {
if (key.starts_with("#")) { if (key.starts_with("lexer.*")) {
// Ignore comments
} else if (key.starts_with("lexer.*")) {
// Ignore as processed earlier // Ignore as processed earlier
} else if (key.starts_with("keywords")) { } else if (key.starts_with("keywords")) {
// Ignore as processed earlier // Ignore as processed earlier
@ -455,16 +792,16 @@ bool TestFile(const std::filesystem::path &path, const PropertyMap &propertyMap)
plex->Release(); plex->Release();
if (success) {
Scintilla::ILexer5 *plexCRLF = Lexilla::MakeLexer(*language); Scintilla::ILexer5 *plexCRLF = Lexilla::MakeLexer(*language);
SetProperties(plexCRLF, propertyMap, path.filename().string()); SetProperties(plexCRLF, propertyMap, path.filename().string());
TestCRLF(path, text, plexCRLF, disablePerLineTests); success = TestCRLF(path, text, plexCRLF, disablePerLineTests);
}
return success; return success;
} }
bool TestDirectory(std::filesystem::path directory, std::filesystem::path basePath) { bool TestDirectory(std::filesystem::path directory, std::filesystem::path basePath) {
PropertyMap properties;
properties.ReadFromFile(directory / "SciTE.properties");
bool success = true; bool success = true;
for (auto &p : std::filesystem::directory_iterator(directory)) { for (auto &p : std::filesystem::directory_iterator(directory)) {
if (!p.is_directory()) { if (!p.is_directory()) {
@ -473,6 +810,9 @@ bool TestDirectory(std::filesystem::path directory, std::filesystem::path basePa
extension != suffixFolded) { extension != suffixFolded) {
const std::filesystem::path relativePath = p.path().lexically_relative(basePath); const std::filesystem::path relativePath = p.path().lexically_relative(basePath);
std::cout << "Lexing " << relativePath.string() << '\n'; std::cout << "Lexing " << relativePath.string() << '\n';
PropertyMap properties;
properties.properties["FileNameExt"] = p.path().filename().string();
properties.ReadFromFile(directory / "SciTE.properties");
if (!TestFile(p, properties)) { if (!TestFile(p, properties)) {
success = false; success = false;
} }

View File

@ -1,3 +1,9 @@
code.page=65001 code.page=65001
lexer.*.md=markdown lexer.*.md=markdown
fold=1 fold=1
# Tests for the lexer.markdown.header.eolfill property, issue #62
if $(= $(FileNameExt);HeaderEOLFill_0.md)
lexer.markdown.header.eolfill=0
if $(= $(FileNameExt);HeaderEOLFill_1.md)
lexer.markdown.header.eolfill=1

View File

@ -1,3 +1,4 @@
lexer.*.rb=ruby lexer.*.rb=ruby
keywords.*.rb=class def end keywords.*.rb=begin class def do end if module return self super true while \
__FILE__ __LINE__
fold=1 fold=1

View File

@ -3,4 +3,4 @@
0 402 0 | i = 1 0 402 0 | i = 1
0 402 0 | puts "Example" 0 402 0 | puts "Example"
0 402 0 | end 0 402 0 | end
0 400 0 end 0 401 0 | end

View File

@ -1 +1 @@
515 516

View File

@ -96,8 +96,7 @@ char ScintillaCall::CharacterAt(Position position) {
} }
int ScintillaCall::UnsignedStyleAt(Position position) { int ScintillaCall::UnsignedStyleAt(Position position) {
// Returns signed value but easier to use as unsigned return static_cast<int>(Call(Message::GetStyleIndexAt, position));
return static_cast<unsigned char>(Call(Message::GetStyleAt, position));
} }
std::string ScintillaCall::StringOfSpan(Span span) { std::string ScintillaCall::StringOfSpan(Span span) {
@ -192,6 +191,10 @@ int ScintillaCall::StyleAt(Position pos) {
return static_cast<int>(Call(Message::GetStyleAt, pos)); return static_cast<int>(Call(Message::GetStyleAt, pos));
} }
int ScintillaCall::StyleIndexAt(Position pos) {
return static_cast<int>(Call(Message::GetStyleIndexAt, pos));
}
void ScintillaCall::Redo() { void ScintillaCall::Redo() {
Call(Message::Redo); Call(Message::Redo);
} }

View File

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

View File

@ -565,7 +565,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 5.2.1; CURRENT_PROJECT_VERSION = 5.2.2;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
@ -627,7 +627,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 5.2.1; CURRENT_PROJECT_VERSION = 5.2.2;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -657,7 +657,7 @@
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5.2.1; CURRENT_PROJECT_VERSION = 5.2.2;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
@ -691,7 +691,7 @@
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5.2.1; CURRENT_PROJECT_VERSION = 5.2.2;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;

View File

@ -1100,7 +1100,7 @@ void ScintillaCocoa::CTPaint(void *gc, NSRect rc) {
#pragma unused(rc) #pragma unused(rc)
std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(Technology::Default)); std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(Technology::Default));
surfaceWindow->Init(gc, wMain.GetID()); surfaceWindow->Init(gc, wMain.GetID());
surfaceWindow->SetMode(SurfaceMode(ct.codePage, BidirectionalR2L())); surfaceWindow->SetMode(CurrentSurfaceMode());
ct.PaintCT(surfaceWindow.get()); ct.PaintCT(surfaceWindow.get());
surfaceWindow->Release(); surfaceWindow->Release();
} }
@ -1456,7 +1456,7 @@ void ScintillaCocoa::StartDrag() {
// To get a bitmap of the text we're dragging, we just use Paint on a pixmap surface. // To get a bitmap of the text we're dragging, we just use Paint on a pixmap surface.
SurfaceImpl si; SurfaceImpl si;
si.SetMode(SurfaceMode(CodePage(), BidirectionalR2L())); si.SetMode(CurrentSurfaceMode());
std::unique_ptr<SurfaceImpl> sw = si.AllocatePixMapImplementation(static_cast<int>(client.Width()), static_cast<int>(client.Height())); std::unique_ptr<SurfaceImpl> sw = si.AllocatePixMapImplementation(static_cast<int>(client.Width()), static_cast<int>(client.Height()));
const bool lastHideSelection = view.hideSelection; const bool lastHideSelection = view.hideSelection;

View File

@ -129,7 +129,7 @@
<h1>Scintilla Documentation</h1> <h1>Scintilla Documentation</h1>
<p>Last edited 2 February 2021 NH</p> <p>Last edited 9 March 2022 NH</p>
<p style="background:#90F0C0">Scintilla 5 has moved the lexers from Scintilla into a new <p style="background:#90F0C0">Scintilla 5 has moved the lexers from Scintilla into a new
<a href="Lexilla.html">Lexilla</a> project.<br /> <a href="Lexilla.html">Lexilla</a> project.<br />
@ -543,6 +543,7 @@
<a class="message" href="#SCI_CLEARDOCUMENTSTYLE">SCI_CLEARDOCUMENTSTYLE</a><br /> <a class="message" href="#SCI_CLEARDOCUMENTSTYLE">SCI_CLEARDOCUMENTSTYLE</a><br />
<a class="message" href="#SCI_GETCHARAT">SCI_GETCHARAT(position pos) &rarr; int</a><br /> <a class="message" href="#SCI_GETCHARAT">SCI_GETCHARAT(position pos) &rarr; int</a><br />
<a class="message" href="#SCI_GETSTYLEAT">SCI_GETSTYLEAT(position pos) &rarr; int</a><br /> <a class="message" href="#SCI_GETSTYLEAT">SCI_GETSTYLEAT(position pos) &rarr; int</a><br />
<a class="message" href="#SCI_GETSTYLEINDEXAT">SCI_GETSTYLEINDEXAT(position pos) &rarr; int</a><br />
<a class="message" href="#SCI_GETSTYLEDTEXT">SCI_GETSTYLEDTEXT(&lt;unused&gt;, Sci_TextRange *tr) &rarr; position</a><br /> <a class="message" href="#SCI_GETSTYLEDTEXT">SCI_GETSTYLEDTEXT(&lt;unused&gt;, Sci_TextRange *tr) &rarr; position</a><br />
<a class="message" href="#SCI_RELEASEALLEXTENDEDSTYLES">SCI_RELEASEALLEXTENDEDSTYLES</a><br /> <a class="message" href="#SCI_RELEASEALLEXTENDEDSTYLES">SCI_RELEASEALLEXTENDEDSTYLES</a><br />
<a class="message" href="#SCI_ALLOCATEEXTENDEDSTYLES">SCI_ALLOCATEEXTENDEDSTYLES(int numberStyles) &rarr; int</a><br /> <a class="message" href="#SCI_ALLOCATEEXTENDEDSTYLES">SCI_ALLOCATEEXTENDEDSTYLES(int numberStyles) &rarr; int</a><br />
@ -694,9 +695,15 @@
This returns the character at <code class="parameter">pos</code> in the document or 0 if <code class="parameter">pos</code> is This returns the character at <code class="parameter">pos</code> in the document or 0 if <code class="parameter">pos</code> is
negative or past the end of the document.</p> negative or past the end of the document.</p>
<p><b id="SCI_GETSTYLEAT">SCI_GETSTYLEAT(position pos) &rarr; int</b><br /> <p>
<b id="SCI_GETSTYLEAT">SCI_GETSTYLEAT(position pos) &rarr; int</b><br />
<b id="SCI_GETSTYLEINDEXAT">SCI_GETSTYLEINDEXAT(position pos) &rarr; int</b><br />
This returns the style at <code class="parameter">pos</code> in the document, or 0 if <code class="parameter">pos</code> is This returns the style at <code class="parameter">pos</code> in the document, or 0 if <code class="parameter">pos</code> is
negative or past the end of the document.</p> negative or past the end of the document.
<code>SCI_GETSTYLEAT</code> may return a negative number for styles over 127 whereas <code>SCI_GETSTYLEINDEXAT</code>
will only return positive numbers.
<code>SCI_GETSTYLEINDEXAT</code> should be preferred as it handles styles more consistently and may avoid problems
with lexers that define more than 128 styles.</p>
<p><b id="SCI_RELEASEALLEXTENDEDSTYLES">SCI_RELEASEALLEXTENDEDSTYLES</b><br /> <p><b id="SCI_RELEASEALLEXTENDEDSTYLES">SCI_RELEASEALLEXTENDEDSTYLES</b><br />
<b id="SCI_ALLOCATEEXTENDEDSTYLES">SCI_ALLOCATEEXTENDEDSTYLES(int numberStyles) &rarr; int</b><br /> <b id="SCI_ALLOCATEEXTENDEDSTYLES">SCI_ALLOCATEEXTENDEDSTYLES(int numberStyles) &rarr; int</b><br />

View File

@ -26,9 +26,9 @@
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0"> <table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
<tr> <tr>
<td> <td>
<font size="4"> <a href="https://www.scintilla.org/scintilla521.zip"> <font size="4"> <a href="https://www.scintilla.org/scintilla522.zip">
Windows</a>&nbsp;&nbsp; Windows</a>&nbsp;&nbsp;
<a href="https://www.scintilla.org/scintilla521.tgz"> <a href="https://www.scintilla.org/scintilla522.tgz">
GTK/Linux</a>&nbsp;&nbsp; GTK/Linux</a>&nbsp;&nbsp;
</font> </font>
</td> </td>
@ -42,7 +42,7 @@
containing very few restrictions. containing very few restrictions.
</p> </p>
<h3> <h3>
Release 5.2.1 Release 5.2.2
</h3> </h3>
<h4> <h4>
Source Code Source Code
@ -50,8 +50,8 @@
The source code package contains all of the source code for Scintilla but no binary The source code package contains all of the source code for Scintilla but no binary
executable code and is available in executable code and is available in
<ul> <ul>
<li><a href="https://www.scintilla.org/scintilla521.zip">zip format</a> (1.3M) commonly used on Windows</li> <li><a href="https://www.scintilla.org/scintilla522.zip">zip format</a> (1.3M) commonly used on Windows</li>
<li><a href="https://www.scintilla.org/scintilla521.tgz">tgz format</a> (1.2M) commonly used on Linux and compatible operating systems</li> <li><a href="https://www.scintilla.org/scintilla522.tgz">tgz format</a> (1.2M) commonly used on Linux and compatible operating systems</li>
</ul> </ul>
Instructions for building on both Windows and Linux are included in the readme file. Instructions for building on both Windows and Linux are included in the readme file.
<h4> <h4>

View File

@ -569,9 +569,37 @@
</tr><tr> </tr><tr>
<td>Arkadiusz Michalski</td> <td>Arkadiusz Michalski</td>
<td>Christian Schmitz</td> <td>Christian Schmitz</td>
<td>Michael Berlenz</td>
</tr> </tr>
</table> </table>
<h2>Releases</h2> <h2>Releases</h2>
<h3>
<a href="https://www.scintilla.org/scintilla522.zip">Release 5.2.2</a>
</h3>
<ul>
<li>
Released 31 March 2022.
</li>
<li>
Add SCI_GETSTYLEINDEXAT API to return styles over 127 as positive integers.
<a href="https://sourceforge.net/p/scintilla/feature-requests/1431/">Feature #1431</a>.
</li>
<li>
On GTK, scroll horizontally with shift + scroll wheel.
</li>
<li>
Fix crash with unexpected right-to-left text on GTK.
<a href="https://sourceforge.net/p/scintilla/bugs/2309/">Bug #2309</a>.
</li>
<li>
Fix position of end-of-line annotation when fold display text is visible.
<a href="https://sourceforge.net/p/scintilla/bugs/2320/">Bug #2320</a>.
</li>
<li>
On Direct2D, support per-monitor text rendering parameters.
<a href="https://sourceforge.net/p/scintilla/feature-requests/1432/">Feature #1432</a>.
</li>
</ul>
<h3> <h3>
<a href="https://www.scintilla.org/scintilla521.zip">Release 5.2.1</a> <a href="https://www.scintilla.org/scintilla521.zip">Release 5.2.1</a>
</h3> </h3>

View File

@ -9,7 +9,7 @@
<meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" /> <meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" />
<meta name="Description" <meta name="Description"
content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." /> content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." />
<meta name="Date.Modified" content="20220224" /> <meta name="Date.Modified" content="20220331" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css"> <style type="text/css">
#versionlist { #versionlist {
@ -56,8 +56,8 @@
GTK, and macOS</font> GTK, and macOS</font>
</td> </td>
<td width="40%" align="right"> <td width="40%" align="right">
<font color="#FFCC99" size="3"> Release version 5.2.1<br /> <font color="#FFCC99" size="3"> Release version 5.2.2<br />
Site last modified February 24 2022</font> Site last modified March 31 2022</font>
</td> </td>
<td width="20%"> <td width="20%">
&nbsp; &nbsp;
@ -72,6 +72,7 @@
</tr> </tr>
</table> </table>
<ul id="versionlist"> <ul id="versionlist">
<li>Version 5.2.2 on GTK, scroll horizontally with Shift + Scroll Wheel.</li>
<li>Version 5.2.1 fixes leaks on GTK.</li> <li>Version 5.2.1 fixes leaks on GTK.</li>
<li>Version 5.2.0 adds multithreaded layout to significantly improve performance for very wide lines.</li> <li>Version 5.2.0 adds multithreaded layout to significantly improve performance for very wide lines.</li>
<li>Version 5.1.5 changes string-returning APIs to be more consistent and removes ScintillaEditPy.</li> <li>Version 5.1.5 changes string-returning APIs to be more consistent and removes ScintillaEditPy.</li>

View File

@ -822,6 +822,8 @@ void SurfaceImpl::DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITI
} }
} }
namespace {
class ClusterIterator { class ClusterIterator {
UniquePangoLayoutIter iter; UniquePangoLayoutIter iter;
PangoRectangle pos {}; PangoRectangle pos {};
@ -836,6 +838,7 @@ public:
lenPositions(static_cast<int>(text.length())) { lenPositions(static_cast<int>(text.length())) {
LayoutSetText(layout, text); LayoutSetText(layout, text);
iter.reset(pango_layout_get_iter(layout)); iter.reset(pango_layout_get_iter(layout));
curIndex = pango_layout_iter_get_index(iter.get());
pango_layout_iter_get_cluster_extents(iter.get(), nullptr, &pos); pango_layout_iter_get_cluster_extents(iter.get(), nullptr, &pos);
} }
@ -848,12 +851,24 @@ public:
} else { } else {
finished = true; finished = true;
position = pango_units_to_double(pos.x + pos.width); position = pango_units_to_double(pos.x + pos.width);
curIndex = lenPositions; curIndex = pango_layout_iter_get_index(iter.get());
} }
distance = position - positionStart; distance = position - positionStart;
} }
}; };
// Something has gone wrong so set all the characters as equally spaced.
void EquallySpaced(PangoLayout *layout, XYPOSITION *positions, size_t lenPositions) {
int widthLayout = 0;
pango_layout_get_size(layout, &widthLayout, nullptr);
const XYPOSITION widthTotal = pango_units_to_double(widthLayout);
for (size_t bytePos=0; bytePos<lenPositions; bytePos++) {
positions[bytePos] = widthTotal / lenPositions * (bytePos + 1);
}
}
}
void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) { void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) {
if (PFont(font_)->fd) { if (PFont(font_)->fd) {
UniquePangoContext contextMeasure = MeasuringContext(); UniquePangoContext contextMeasure = MeasuringContext();
@ -863,8 +878,13 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI
pango_layout_set_font_description(layoutMeasure.get(), PFont(font_)->fd.get()); pango_layout_set_font_description(layoutMeasure.get(), PFont(font_)->fd.get());
if (et == EncodingType::utf8) { if (et == EncodingType::utf8) {
// Simple and direct as UTF-8 is native Pango encoding // Simple and direct as UTF-8 is native Pango encoding
int i = 0;
ClusterIterator iti(layoutMeasure.get(), text); ClusterIterator iti(layoutMeasure.get(), text);
int i = iti.curIndex;
if (i != 0) {
// Unexpected start to iteration, could be bidirectional text
EquallySpaced(layoutMeasure.get(), positions, text.length());
return;
}
while (!iti.finished) { while (!iti.finished) {
iti.Next(); iti.Next();
const int places = iti.curIndex - i; const int places = iti.curIndex - i;
@ -889,8 +909,13 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI
// character byte lengths. // character byte lengths.
Converter convMeasure("UCS-2", CharacterSetID(characterSet), false); Converter convMeasure("UCS-2", CharacterSetID(characterSet), false);
int i = 0; int i = 0;
int clusterStart = 0;
ClusterIterator iti(layoutMeasure.get(), utfForm); ClusterIterator iti(layoutMeasure.get(), utfForm);
int clusterStart = iti.curIndex;
if (clusterStart != 0) {
// Unexpected start to iteration, could be bidirectional text
EquallySpaced(layoutMeasure.get(), positions, text.length());
return;
}
while (!iti.finished) { while (!iti.finished) {
iti.Next(); iti.Next();
const int clusterEnd = iti.curIndex; const int clusterEnd = iti.curIndex;
@ -920,22 +945,22 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI
utfForm = UTF8FromLatin1(text); utfForm = UTF8FromLatin1(text);
} }
size_t i = 0; size_t i = 0;
int clusterStart = 0;
// Each 8-bit input character may take 1 or 2 bytes in UTF-8 // Each 8-bit input character may take 1 or 2 bytes in UTF-8
// and groups of up to 3 may be represented as ligatures. // and groups of up to 3 may be represented as ligatures.
ClusterIterator iti(layoutMeasure.get(), utfForm); ClusterIterator iti(layoutMeasure.get(), utfForm);
int clusterStart = iti.curIndex;
if (clusterStart != 0) {
// Unexpected start to iteration, could be bidirectional text
EquallySpaced(layoutMeasure.get(), positions, lenPositions);
return;
}
while (!iti.finished) { while (!iti.finished) {
iti.Next(); iti.Next();
const int clusterEnd = iti.curIndex; const int clusterEnd = iti.curIndex;
const int ligatureLength = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart); const int ligatureLength = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart);
if (rtlCheck && ((clusterEnd <= clusterStart) || (ligatureLength == 0) || (ligatureLength > 3))) { if (rtlCheck && ((clusterEnd <= clusterStart) || (ligatureLength == 0) || (ligatureLength > 3))) {
// Something has gone wrong: exit quickly but pretend all the characters are equally spaced: // Something has gone wrong: exit quickly but pretend all the characters are equally spaced:
int widthLayout = 0; EquallySpaced(layoutMeasure.get(), positions, lenPositions);
pango_layout_get_size(layoutMeasure.get(), &widthLayout, nullptr);
const XYPOSITION widthTotal = pango_units_to_double(widthLayout);
for (size_t bytePos=0; bytePos<lenPositions; bytePos++) {
positions[bytePos] = widthTotal / lenPositions * (bytePos + 1);
}
return; return;
} }
PLATFORM_ASSERT(ligatureLength > 0 && ligatureLength <= 3); PLATFORM_ASSERT(ligatureLength > 0 && ligatureLength <= 3);
@ -1029,8 +1054,13 @@ void SurfaceImpl::MeasureWidthsUTF8(const Font *font_, std::string_view text, XY
pango_layout_set_font_description(layoutMeasure.get(), PFont(font_)->fd.get()); pango_layout_set_font_description(layoutMeasure.get(), PFont(font_)->fd.get());
// Simple and direct as UTF-8 is native Pango encoding // Simple and direct as UTF-8 is native Pango encoding
int i = 0;
ClusterIterator iti(layoutMeasure.get(), text); ClusterIterator iti(layoutMeasure.get(), text);
int i = iti.curIndex;
if (i != 0) {
// Unexpected start to iteration, could be bidirectional text
EquallySpaced(layoutMeasure.get(), positions, text.length());
return;
}
while (!iti.finished) { while (!iti.finished) {
iti.Next(); iti.Next();
const int places = iti.curIndex - i; const int places = iti.curIndex - i;

View File

@ -1999,11 +1999,6 @@ gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) {
// issues spurious button 2 mouse events during wheeling, which can cause // issues spurious button 2 mouse events during wheeling, which can cause
// problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001) // problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
// Data zoom not supported
if (event->state & GDK_SHIFT_MASK) {
return FALSE;
}
#if GTK_CHECK_VERSION(3,4,0) #if GTK_CHECK_VERSION(3,4,0)
// Smooth scrolling not supported // Smooth scrolling not supported
if (event->direction == GDK_SCROLL_SMOOTH) { if (event->direction == GDK_SCROLL_SMOOTH) {
@ -2012,8 +2007,10 @@ gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) {
#endif #endif
// Horizontal scrolling // Horizontal scrolling
if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT) { if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT || event->state & GDK_SHIFT_MASK) {
sciThis->HorizontalScrollTo(sciThis->xOffset + cLineScroll); int hScroll = gtk_adjustment_get_step_increment(sciThis->adjustmenth);
hScroll *= cLineScroll; // scroll by this many characters
sciThis->HorizontalScrollTo(sciThis->xOffset + hScroll);
// Text font size zoom // Text font size zoom
} else if (event->state & GDK_CONTROL_MASK) { } else if (event->state & GDK_CONTROL_MASK) {

View File

@ -15,10 +15,8 @@
typedef ptrdiff_t Sci_Position; typedef ptrdiff_t Sci_Position;
// Unsigned variant used for ILexer::Lex and ILexer::Fold // Unsigned variant used for ILexer::Lex and ILexer::Fold
// Definitions of common types
typedef size_t Sci_PositionU; typedef size_t Sci_PositionU;
// For Sci_CharacterRange which is defined as long to be compatible with Win32 CHARRANGE // For Sci_CharacterRange which is defined as long to be compatible with Win32 CHARRANGE
typedef intptr_t Sci_PositionCR; typedef intptr_t Sci_PositionCR;

View File

@ -57,6 +57,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP
#define SCI_GETCURRENTPOS 2008 #define SCI_GETCURRENTPOS 2008
#define SCI_GETANCHOR 2009 #define SCI_GETANCHOR 2009
#define SCI_GETSTYLEAT 2010 #define SCI_GETSTYLEAT 2010
#define SCI_GETSTYLEINDEXAT 2038
#define SCI_REDO 2011 #define SCI_REDO 2011
#define SCI_SETUNDOCOLLECTION 2012 #define SCI_SETUNDOCOLLECTION 2012
#define SCI_SELECTALL 2013 #define SCI_SELECTALL 2013

View File

@ -130,6 +130,9 @@ get position GetAnchor=2009(,)
# Returns the style byte at the position. # Returns the style byte at the position.
get int GetStyleAt=2010(position pos,) get int GetStyleAt=2010(position pos,)
# Returns the unsigned style byte at the position.
get int GetStyleIndexAt=2038(position pos,)
# Redoes the next action on the undo history. # Redoes the next action on the undo history.
fun void Redo=2011(,) fun void Redo=2011(,)

View File

@ -88,6 +88,7 @@ public:
Position CurrentPos(); Position CurrentPos();
Position Anchor(); Position Anchor();
int StyleAt(Position pos); int StyleAt(Position pos);
int StyleIndexAt(Position pos);
void Redo(); void Redo();
void SetUndoCollection(bool collectUndo); void SetUndoCollection(bool collectUndo);
void SelectAll(); void SelectAll();

View File

@ -28,6 +28,7 @@ enum class Message {
GetCurrentPos = 2008, GetCurrentPos = 2008,
GetAnchor = 2009, GetAnchor = 2009,
GetStyleAt = 2010, GetStyleAt = 2010,
GetStyleIndexAt = 2038,
Redo = 2011, Redo = 2011,
SetUndoCollection = 2012, SetUndoCollection = 2012,
SelectAll = 2013, SelectAll = 2013,

View File

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

View File

@ -339,19 +339,8 @@ void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern)
{ {
// Tile pattern over rectangle // Tile pattern over rectangle
SurfaceImpl *surface = dynamic_cast<SurfaceImpl *>(&surfacePattern); SurfaceImpl *surface = dynamic_cast<SurfaceImpl *>(&surfacePattern);
// Currently assumes 8x8 pattern const QPixmap *pixmap = static_cast<QPixmap *>(surface->GetPaintDevice());
int widthPat = 8; GetPainter()->drawTiledPixmap(QRectFromPRect(rc), *pixmap);
int heightPat = 8;
for (int xTile = rc.left; xTile < rc.right; xTile += widthPat) {
int widthx = (xTile + widthPat > rc.right) ? rc.right - xTile : widthPat;
for (int yTile = rc.top; yTile < rc.bottom; yTile += heightPat) {
int heighty = (yTile + heightPat > rc.bottom) ? rc.bottom - yTile : heightPat;
QRect source(0, 0, widthx, heighty);
QRect target(xTile, yTile, widthx, heighty);
QPixmap *pixmap = static_cast<QPixmap *>(surface->GetPaintDevice());
GetPainter()->drawPixmap(target, *pixmap, source);
}
}
} }
void SurfaceImpl::RoundedRectangle(PRectangle rc, FillStroke fillStroke) void SurfaceImpl::RoundedRectangle(PRectangle rc, FillStroke fillStroke)

View File

@ -12,7 +12,7 @@ TEMPLATE = lib
CONFIG += lib_bundle CONFIG += lib_bundle
CONFIG += c++1z CONFIG += c++1z
VERSION = 5.2.1 VERSION = 5.2.2
SOURCES += \ SOURCES += \
PlatQt.cpp \ PlatQt.cpp \

View File

@ -272,24 +272,14 @@ void CallTip::MouseClick(Point pt) noexcept {
} }
PRectangle CallTip::CallTipStart(Sci::Position pos, Point pt, int textHeight, const char *defn, PRectangle CallTip::CallTipStart(Sci::Position pos, Point pt, int textHeight, const char *defn,
const char *faceName, int size, int codePage_, Surface *surfaceMeasure, std::shared_ptr<Font> font_) {
int codePage_, CharacterSet characterSet,
Technology technology,
const char *localeName,
const Window &wParent) {
clickPlace = 0; clickPlace = 0;
val = defn; val = defn;
codePage = codePage_; codePage = codePage_;
std::unique_ptr<Surface> surfaceMeasure = Surface::Allocate(technology);
surfaceMeasure->Init(wParent.GetID());
surfaceMeasure->SetMode(SurfaceMode(codePage, false));
highlight = Chunk(); highlight = Chunk();
inCallTipMode = true; inCallTipMode = true;
posStartCallTip = pos; posStartCallTip = pos;
const XYPOSITION deviceHeight = static_cast<XYPOSITION>(surfaceMeasure->DeviceHeightFont(size)); font = font_;
const FontParameters fp(faceName, deviceHeight / FontSizeMultiplier, FontWeight::Normal,
false, FontQuality::QualityDefault, technology, characterSet, localeName);
font = Font::Allocate(fp);
// Look for multiple lines in the text // Look for multiple lines in the text
// Only support \n here - simply means container must avoid \r! // Only support \n here - simply means container must avoid \r!
const int numLines = 1 + static_cast<int>(std::count(val.begin(), val.end(), '\n')); const int numLines = 1 + static_cast<int>(std::count(val.begin(), val.end(), '\n'));
@ -300,7 +290,7 @@ PRectangle CallTip::CallTipStart(Sci::Position pos, Point pt, int textHeight, co
#if !PLAT_CURSES #if !PLAT_CURSES
widthArrow = lineHeight * 9 / 10; widthArrow = lineHeight * 9 / 10;
#endif #endif
const int width = PaintContents(surfaceMeasure.get(), false) + insetX; const int width = PaintContents(surfaceMeasure, false) + insetX;
// The returned // The returned
// rectangle is aligned to the right edge of the last arrow encountered in // rectangle is aligned to the right edge of the last arrow encountered in
@ -350,7 +340,7 @@ bool CallTip::UseStyleCallTip() const noexcept {
// It might be better to have two access functions for this and to use // It might be better to have two access functions for this and to use
// them for all settings of colours. // them for all settings of colours.
void CallTip::SetForeBack(const ColourRGBA &fore, const ColourRGBA &back) noexcept { void CallTip::SetForeBack(ColourRGBA fore, ColourRGBA back) noexcept {
colourBG = back; colourBG = back;
colourUnSel = fore; colourUnSel = fore;
} }

View File

@ -71,9 +71,7 @@ public:
/// Setup the calltip and return a rectangle of the area required. /// Setup the calltip and return a rectangle of the area required.
PRectangle CallTipStart(Sci::Position pos, Point pt, int textHeight, const char *defn, PRectangle CallTipStart(Sci::Position pos, Point pt, int textHeight, const char *defn,
const char *faceName, int size, int codePage_, int codePage_, Surface *surfaceMeasure, std::shared_ptr<Font> font_);
Scintilla::CharacterSet characterSet, Scintilla::Technology technology, const char *localeName,
const Window &wParent);
void CallTipCancel() noexcept; void CallTipCancel() noexcept;
@ -91,7 +89,7 @@ public:
bool UseStyleCallTip() const noexcept; bool UseStyleCallTip() const noexcept;
// Modify foreground and background colours // Modify foreground and background colours
void SetForeBack(const ColourRGBA &fore, const ColourRGBA &back) noexcept; void SetForeBack(ColourRGBA fore, ColourRGBA back) noexcept;
}; };
} }

View File

@ -101,6 +101,10 @@ bool EditModel::BidirectionalR2L() const noexcept {
return bidirectional == Bidirectional::R2L; return bidirectional == Bidirectional::R2L;
} }
SurfaceMode EditModel::CurrentSurfaceMode() const noexcept {
return SurfaceMode(pdoc->dbcsCodePage, BidirectionalR2L());
}
void EditModel::SetDefaultFoldDisplayText(const char *text) { void EditModel::SetDefaultFoldDisplayText(const char *text) {
defaultFoldDisplayText = IsNullOrEmpty(text) ? UniqueString() : UniqueStringCopy(text); defaultFoldDisplayText = IsNullOrEmpty(text) ? UniqueString() : UniqueStringCopy(text);
} }

View File

@ -66,6 +66,7 @@ public:
virtual Sci::Line LinesOnScreen() const = 0; virtual Sci::Line LinesOnScreen() const = 0;
bool BidirectionalEnabled() const noexcept; bool BidirectionalEnabled() const noexcept;
bool BidirectionalR2L() const noexcept; bool BidirectionalR2L() const noexcept;
SurfaceMode CurrentSurfaceMode() const noexcept;
void SetDefaultFoldDisplayText(const char *text); void SetDefaultFoldDisplayText(const char *text);
const char *GetDefaultFoldDisplayText() const noexcept; const char *GetDefaultFoldDisplayText() const noexcept;
const char *GetFoldDisplayText(Sci::Line lineDoc) const noexcept; const char *GetFoldDisplayText(Sci::Line lineDoc) const noexcept;

View File

@ -774,8 +774,8 @@ Point EditView::LocationFromPosition(Surface *surface, const EditModel &model, S
} }
} }
pt.y += (lineVisible - topLine) * vs.lineHeight; pt.y += (lineVisible - topLine) * vs.lineHeight;
}
pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth; pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth;
}
return pt; return pt;
} }
@ -1485,7 +1485,9 @@ void EditView::DrawEOLAnnotationText(Surface *surface, const EditModel &model, c
const char *textFoldDisplay = model.GetFoldDisplayText(line); const char *textFoldDisplay = model.GetFoldDisplayText(line);
if (textFoldDisplay) { if (textFoldDisplay) {
const std::string_view foldDisplayText(textFoldDisplay); const std::string_view foldDisplayText(textFoldDisplay);
rcSegment.left += (static_cast<int>(surface->WidthText(fontText, foldDisplayText)) + vsDraw.aveCharWidth); rcSegment.left += static_cast<int>(
surface->WidthText(vsDraw.styles[StyleFoldDisplayText].font.get(), foldDisplayText)) +
vsDraw.aveCharWidth;
} }
rcSegment.right = rcSegment.left + static_cast<XYPOSITION>(widthEOLAnnotationText); rcSegment.right = rcSegment.left + static_cast<XYPOSITION>(widthEOLAnnotationText);
@ -2441,7 +2443,7 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectan
surface = pixmapLine.get(); surface = pixmapLine.get();
PLATFORM_ASSERT(pixmapLine->Initialised()); PLATFORM_ASSERT(pixmapLine->Initialised());
} }
surface->SetMode(SurfaceMode(model.pdoc->dbcsCodePage, model.BidirectionalR2L())); surface->SetMode(model.CurrentSurfaceMode());
const Point ptOrigin = model.GetVisibleOriginInMain(); const Point ptOrigin = model.GetVisibleOriginInMain();

View File

@ -204,7 +204,6 @@ Editor::Editor() : durationWrapOneByte(0.000001, 0.00000001, 0.00001) {
Editor::~Editor() { Editor::~Editor() {
pdoc->RemoveWatcher(this, nullptr); pdoc->RemoveWatcher(this, nullptr);
DropGraphics();
} }
void Editor::Finalise() { void Editor::Finalise() {
@ -1707,6 +1706,7 @@ void Editor::PaintSelMargin(Surface *surfaceWindow, const PRectangle &rc) {
} else { } else {
surface = surfaceWindow; surface = surfaceWindow;
} }
surface->SetMode(CurrentSurfaceMode());
// Clip vertically to paint area to avoid drawing line numbers // Clip vertically to paint area to avoid drawing line numbers
if (rcMargin.bottom > rc.bottom) if (rcMargin.bottom > rc.bottom)
@ -5687,6 +5687,26 @@ int Editor::CodePage() const noexcept {
return 0; return 0;
} }
std::unique_ptr<Surface> Editor::CreateMeasurementSurface() const {
if (!wMain.GetID()) {
return {};
}
std::unique_ptr<Surface> surf = Surface::Allocate(technology);
surf->Init(wMain.GetID());
surf->SetMode(CurrentSurfaceMode());
return surf;
}
std::unique_ptr<Surface> Editor::CreateDrawingSurface(SurfaceID sid, std::optional<Scintilla::Technology> technologyOpt) const {
if (!wMain.GetID()) {
return {};
}
std::unique_ptr<Surface> surf = Surface::Allocate(technologyOpt ? *technologyOpt : technology);
surf->Init(sid, wMain.GetID());
surf->SetMode(CurrentSurfaceMode());
return surf;
}
Sci::Line Editor::WrapCount(Sci::Line line) { Sci::Line Editor::WrapCount(Sci::Line line) {
AutoSurface surface(this); AutoSurface surface(this);
std::shared_ptr<LineLayout> ll = view.RetrieveLineLayout(line, *this); std::shared_ptr<LineLayout> ll = view.RetrieveLineLayout(line, *this);
@ -6464,6 +6484,12 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
else else
return pdoc->StyleAt(PositionFromUPtr(wParam)); return pdoc->StyleAt(PositionFromUPtr(wParam));
case Message::GetStyleIndexAt:
if (PositionFromUPtr(wParam) >= pdoc->Length())
return 0;
else
return pdoc->StyleIndexAt(PositionFromUPtr(wParam));
case Message::Redo: case Message::Redo:
Redo(); Redo();
break; break;

View File

@ -592,6 +592,8 @@ protected: // ScintillaBase subclass needs access to much of Editor
virtual bool ValidCodePage(int /* codePage */) const { return true; } virtual bool ValidCodePage(int /* codePage */) const { return true; }
virtual std::string UTF8FromEncoded(std::string_view encoded) const = 0; virtual std::string UTF8FromEncoded(std::string_view encoded) const = 0;
virtual std::string EncodedFromUTF8(std::string_view utf8) const = 0; virtual std::string EncodedFromUTF8(std::string_view utf8) const = 0;
virtual std::unique_ptr<Surface> CreateMeasurementSurface() const;
virtual std::unique_ptr<Surface> CreateDrawingSurface(SurfaceID sid, std::optional<Scintilla::Technology> technologyOpt = {}) const;
Sci::Line WrapCount(Sci::Line line); Sci::Line WrapCount(Sci::Line line);
void AddStyledText(const char *buffer, Sci::Position appendLength); void AddStyledText(const char *buffer, Sci::Position appendLength);
@ -684,19 +686,11 @@ class AutoSurface {
private: private:
std::unique_ptr<Surface> surf; std::unique_ptr<Surface> surf;
public: public:
AutoSurface(const Editor *ed) { AutoSurface(const Editor *ed) :
if (ed->wMain.GetID()) { surf(ed->CreateMeasurementSurface()) {
surf = Surface::Allocate(ed->technology);
surf->Init(ed->wMain.GetID());
surf->SetMode(SurfaceMode(ed->CodePage(), ed->BidirectionalR2L()));
}
}
AutoSurface(SurfaceID sid, Editor *ed, std::optional<Scintilla::Technology> technology = {}) {
if (ed->wMain.GetID()) {
surf = Surface::Allocate(technology ? *technology : ed->technology);
surf->Init(sid, ed->wMain.GetID());
surf->SetMode(SurfaceMode(ed->CodePage(), ed->BidirectionalR2L()));
} }
AutoSurface(SurfaceID sid, Editor *ed, std::optional<Scintilla::Technology> technology = {}) :
surf(ed->CreateDrawingSurface(sid, technology)) {
} }
// Deleted so AutoSurface objects can not be copied. // Deleted so AutoSurface objects can not be copied.
AutoSurface(const AutoSurface &) = delete; AutoSurface(const AutoSurface &) = delete;

View File

@ -465,22 +465,20 @@ void ScintillaBase::CallTipShow(Point pt, const char *defn) {
// StyleDefault for the face name, size and character set. Also use it // StyleDefault for the face name, size and character set. Also use it
// for the foreground and background colour. // for the foreground and background colour.
const int ctStyle = ct.UseStyleCallTip() ? StyleCallTip : StyleDefault; const int ctStyle = ct.UseStyleCallTip() ? StyleCallTip : StyleDefault;
const Style &style = vs.styles[ctStyle];
if (ct.UseStyleCallTip()) { if (ct.UseStyleCallTip()) {
ct.SetForeBack(vs.styles[StyleCallTip].fore, vs.styles[StyleCallTip].back); ct.SetForeBack(style.fore, style.back);
} }
if (wMargin.Created()) { if (wMargin.Created()) {
pt = pt + GetVisibleOriginInMain(); pt = pt + GetVisibleOriginInMain();
} }
AutoSurface surfaceMeasure(this);
PRectangle rc = ct.CallTipStart(sel.MainCaret(), pt, PRectangle rc = ct.CallTipStart(sel.MainCaret(), pt,
vs.lineHeight, vs.lineHeight,
defn, defn,
vs.styles[ctStyle].fontName,
vs.styles[ctStyle].sizeZoomed,
CodePage(), CodePage(),
vs.styles[ctStyle].characterSet, surfaceMeasure,
vs.technology, style.font);
vs.localeName.c_str(),
wMain);
// If the call-tip window would be out of the client // If the call-tip window would be out of the client
// space // space
const PRectangle rcClient = GetClientRectangle(); const PRectangle rcClient = GetClientRectangle();

View File

@ -133,7 +133,6 @@ ViewStyle::ViewStyle(size_t stylesSize_) :
Element::SelectionSecondaryText, Element::SelectionSecondaryText,
Element::SelectionSecondaryBack, Element::SelectionSecondaryBack,
Element::SelectionInactiveText, Element::SelectionInactiveText,
Element::SelectionBack,
Element::SelectionInactiveBack, Element::SelectionInactiveBack,
}); });

View File

@ -48,13 +48,16 @@ class TestSimple(unittest.TestCase):
def testAddStyledText(self): def testAddStyledText(self):
self.assertEquals(self.ed.EndStyled, 0) self.assertEquals(self.ed.EndStyled, 0)
self.ed.AddStyledText(2, b"x\002") self.ed.AddStyledText(4, b"x\002y\377")
self.assertEquals(self.ed.Length, 1) self.assertEquals(self.ed.Length, 2)
self.assertEquals(self.ed.GetCharAt(0), ord("x")) self.assertEquals(self.ed.GetCharAt(0), ord("x"))
self.assertEquals(self.ed.GetStyleAt(0), 2) self.assertEquals(self.ed.GetStyleAt(0), 2)
self.assertEquals(self.ed.GetStyleIndexAt(0), 2)
self.assertEquals(self.ed.GetStyleIndexAt(1), 255)
self.assertEquals(self.ed.StyledTextRange(0, 1), b"x\002") self.assertEquals(self.ed.StyledTextRange(0, 1), b"x\002")
self.assertEquals(self.ed.StyledTextRange(1, 2), b"y\377")
self.ed.ClearDocumentStyle() self.ed.ClearDocumentStyle()
self.assertEquals(self.ed.Length, 1) self.assertEquals(self.ed.Length, 2)
self.assertEquals(self.ed.GetCharAt(0), ord("x")) self.assertEquals(self.ed.GetCharAt(0), ord("x"))
self.assertEquals(self.ed.GetStyleAt(0), 0) self.assertEquals(self.ed.GetStyleAt(0), 0)
self.assertEquals(self.ed.StyledTextRange(0, 1), b"x\0") self.assertEquals(self.ed.StyledTextRange(0, 1), b"x\0")

View File

@ -1 +1 @@
521 522

View File

@ -19,14 +19,6 @@
namespace Scintilla::Internal::HanjaDict { namespace Scintilla::Internal::HanjaDict {
struct BSTRDeleter {
void operator()(BSTR bstr) const noexcept {
SysFreeString(bstr);
}
};
using UniqueBSTR = std::unique_ptr<OLECHAR[], BSTRDeleter>;
interface IRadical; interface IRadical;
interface IHanja; interface IHanja;
interface IStrokes; interface IStrokes;
@ -66,6 +58,37 @@ interface IHanjaDic : IUnknown {
extern "C" const GUID __declspec(selectany) IID_IHanjaDic = extern "C" const GUID __declspec(selectany) IID_IHanjaDic =
{ 0xad75f3ac, 0x18cd, 0x48c6, { 0xa2, 0x7d, 0xf1, 0xe9, 0xa7, 0xdc, 0xe4, 0x32 } }; { 0xad75f3ac, 0x18cd, 0x48c6, { 0xa2, 0x7d, 0xf1, 0xe9, 0xa7, 0xdc, 0xe4, 0x32 } };
class ScopedBSTR {
BSTR bstr = nullptr;
public:
ScopedBSTR() noexcept = default;
explicit ScopedBSTR(const OLECHAR *psz) noexcept :
bstr(SysAllocString(psz)) {
}
explicit ScopedBSTR(OLECHAR character) noexcept :
bstr(SysAllocStringLen(&character, 1)) {
}
// Deleted so ScopedBSTR objects can not be copied. Moves are OK.
ScopedBSTR(const ScopedBSTR &) = delete;
ScopedBSTR &operator=(const ScopedBSTR &) = delete;
// Moves are OK.
ScopedBSTR(ScopedBSTR &&) = default;
ScopedBSTR &operator=(ScopedBSTR &&) = default;
~ScopedBSTR() {
SysFreeString(bstr);
}
BSTR get() const noexcept {
return bstr;
}
void reset(BSTR value=nullptr) noexcept {
// https://en.cppreference.com/w/cpp/memory/unique_ptr/reset
BSTR const old = bstr;
bstr = value;
SysFreeString(old);
}
};
class HanjaDic { class HanjaDic {
std::unique_ptr<IHanjaDic, UnknownReleaser> HJinterface; std::unique_ptr<IHanjaDic, UnknownReleaser> HJinterface;
@ -77,7 +100,7 @@ class HanjaDic {
hr = CoCreateInstance(CLSID_HanjaDic, nullptr, hr = CoCreateInstance(CLSID_HanjaDic, nullptr,
CLSCTX_INPROC_SERVER, IID_IHanjaDic, CLSCTX_INPROC_SERVER, IID_IHanjaDic,
(LPVOID *)&instance); (LPVOID *)&instance);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr) && instance) {
HJinterface.reset(instance); HJinterface.reset(instance);
hr = instance->OpenMainDic(); hr = instance->OpenMainDic();
return SUCCEEDED(hr); return SUCCEEDED(hr);
@ -102,9 +125,9 @@ public:
return SUCCEEDED(hr) && hanjaType > HANJA_UNKNOWN; return SUCCEEDED(hr) && hanjaType > HANJA_UNKNOWN;
} }
bool HanjaToHangul(BSTR bstrHanja, UniqueBSTR &bstrHangul) const noexcept { bool HanjaToHangul(const ScopedBSTR &bstrHanja, ScopedBSTR &bstrHangul) const noexcept {
BSTR result = nullptr; BSTR result = nullptr;
const HRESULT hr = HJinterface->HanjaToHangul(bstrHanja, &result); const HRESULT hr = HJinterface->HanjaToHangul(bstrHanja.get(), &result);
bstrHangul.reset(result); bstrHangul.reset(result);
return SUCCEEDED(hr); return SUCCEEDED(hr);
} }
@ -121,11 +144,10 @@ bool GetHangulOfHanja(std::wstring &inout) noexcept {
if (dict.Open()) { if (dict.Open()) {
for (wchar_t &character : inout) { for (wchar_t &character : inout) {
if (dict.IsHanja(character)) { // Pass hanja only! if (dict.IsHanja(character)) { // Pass hanja only!
const UniqueBSTR bstrHanja{SysAllocStringLen(&character, 1)}; ScopedBSTR bstrHangul;
UniqueBSTR bstrHangul; if (dict.HanjaToHangul(ScopedBSTR(character), bstrHangul)) {
if (dict.HanjaToHangul(bstrHanja.get(), bstrHangul)) {
changed = true; changed = true;
character = bstrHangul[0]; character = *(bstrHangul.get());
} }
} }
} }

View File

@ -28,9 +28,9 @@
#define NOMINMAX #define NOMINMAX
#endif #endif
#undef _WIN32_WINNT #undef _WIN32_WINNT
#define _WIN32_WINNT 0x0500 #define _WIN32_WINNT 0x0A00
#undef WINVER #undef WINVER
#define WINVER 0x0500 #define WINVER 0x0A00
#define WIN32_LEAN_AND_MEAN 1 #define WIN32_LEAN_AND_MEAN 1
#include <windows.h> #include <windows.h>
#include <commctrl.h> #include <commctrl.h>
@ -58,14 +58,6 @@
#include "WinTypes.h" #include "WinTypes.h"
#include "PlatWin.h" #include "PlatWin.h"
#ifndef SPI_GETFONTSMOOTHINGCONTRAST
#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
#endif
#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
#endif
// __uuidof is a Microsoft extension but makes COM code neater, so disable warning // __uuidof is a Microsoft extension but makes COM code neater, so disable warning
#if defined(__clang__) #if defined(__clang__)
#pragma clang diagnostic ignored "-Wlanguage-extension-token" #pragma clang diagnostic ignored "-Wlanguage-extension-token"
@ -80,8 +72,6 @@ UINT CodePageFromCharSet(CharacterSet characterSet, UINT documentCodePage) noexc
#if defined(USE_D2D) #if defined(USE_D2D)
IDWriteFactory *pIDWriteFactory = nullptr; IDWriteFactory *pIDWriteFactory = nullptr;
ID2D1Factory *pD2DFactory = nullptr; ID2D1Factory *pD2DFactory = nullptr;
IDWriteRenderingParams *defaultRenderingParams = nullptr;
IDWriteRenderingParams *customClearTypeRenderingParams = nullptr;
D2D1_DRAW_TEXT_OPTIONS d2dDrawTextOptions = D2D1_DRAW_TEXT_OPTIONS_NONE; D2D1_DRAW_TEXT_OPTIONS d2dDrawTextOptions = D2D1_DRAW_TEXT_OPTIONS_NONE;
static HMODULE hDLLD2D {}; static HMODULE hDLLD2D {};
@ -131,24 +121,6 @@ void LoadD2DOnce() noexcept {
reinterpret_cast<IUnknown**>(&pIDWriteFactory)); reinterpret_cast<IUnknown**>(&pIDWriteFactory));
} }
} }
if (pIDWriteFactory) {
const HRESULT hr = pIDWriteFactory->CreateRenderingParams(&defaultRenderingParams);
if (SUCCEEDED(hr)) {
unsigned int clearTypeContrast = 0;
if (::SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &clearTypeContrast, 0)) {
FLOAT gamma;
if (clearTypeContrast >= 1000 && clearTypeContrast <= 2200)
gamma = static_cast<FLOAT>(clearTypeContrast) / 1000.0f;
else
gamma = defaultRenderingParams->GetGamma();
pIDWriteFactory->CreateCustomRenderingParams(gamma, defaultRenderingParams->GetEnhancedContrast(), defaultRenderingParams->GetClearTypeLevel(),
defaultRenderingParams->GetPixelGeometry(), defaultRenderingParams->GetRenderingMode(), &customClearTypeRenderingParams);
}
}
}
} }
bool LoadD2D() { bool LoadD2D() {
@ -159,10 +131,6 @@ bool LoadD2D() {
#endif #endif
#ifndef CLEARTYPE_QUALITY
#define CLEARTYPE_QUALITY 5
#endif
void *PointerFromWindow(HWND hWnd) noexcept { void *PointerFromWindow(HWND hWnd) noexcept {
return reinterpret_cast<void *>(::GetWindowLongPtr(hWnd, 0)); return reinterpret_cast<void *>(::GetWindowLongPtr(hWnd, 0));
} }
@ -1307,7 +1275,7 @@ constexpr D2D1_RECT_F RectangleInset(D2D1_RECT_F rect, FLOAT inset) noexcept {
class BlobInline; class BlobInline;
class SurfaceD2D : public Surface { class SurfaceD2D : public Surface, public ISetRenderingParams {
SurfaceMode mode; SurfaceMode mode;
ID2D1RenderTarget *pRenderTarget = nullptr; ID2D1RenderTarget *pRenderTarget = nullptr;
@ -1317,8 +1285,10 @@ class SurfaceD2D : public Surface {
ID2D1SolidColorBrush *pBrush = nullptr; ID2D1SolidColorBrush *pBrush = nullptr;
FontQuality fontQuality = FontQuality::QualityMask; static constexpr FontQuality invalidFontQuality = FontQuality::QualityMask;
FontQuality fontQuality = invalidFontQuality;
int logPixelsY = USER_DEFAULT_SCREEN_DPI; int logPixelsY = USER_DEFAULT_SCREEN_DPI;
std::shared_ptr<RenderingParams> renderingParams;
void Clear() noexcept; void Clear() noexcept;
void SetFontQuality(FontQuality extraFontFlag); void SetFontQuality(FontQuality extraFontFlag);
@ -1392,6 +1362,8 @@ public:
void PopClip() override; void PopClip() override;
void FlushCachedState() override; void FlushCachedState() override;
void FlushDrawing() override; void FlushDrawing() override;
void SetRenderingParams(std::shared_ptr<RenderingParams> renderingParams_) override;
}; };
SurfaceD2D::SurfaceD2D() noexcept { SurfaceD2D::SurfaceD2D() noexcept {
@ -1443,7 +1415,7 @@ void SurfaceD2D::Release() noexcept {
} }
void SurfaceD2D::SetScale(WindowID wid) noexcept { void SurfaceD2D::SetScale(WindowID wid) noexcept {
fontQuality = FontQuality::QualityMask; fontQuality = invalidFontQuality;
logPixelsY = DpiForWindow(wid); logPixelsY = DpiForWindow(wid);
} }
@ -1471,7 +1443,9 @@ void SurfaceD2D::Init(SurfaceID sid, WindowID wid) {
} }
std::unique_ptr<Surface> SurfaceD2D::AllocatePixMap(int width, int height) { std::unique_ptr<Surface> SurfaceD2D::AllocatePixMap(int width, int height) {
return std::make_unique<SurfaceD2D>(pRenderTarget, width, height, mode, logPixelsY); std::unique_ptr<SurfaceD2D> surf = std::make_unique<SurfaceD2D>(pRenderTarget, width, height, mode, logPixelsY);
surf->SetRenderingParams(renderingParams);
return surf;
} }
void SurfaceD2D::SetMode(SurfaceMode mode_) { void SurfaceD2D::SetMode(SurfaceMode mode_) {
@ -1498,15 +1472,14 @@ void SurfaceD2D::D2DPenColourAlpha(ColourRGBA fore) noexcept {
} }
void SurfaceD2D::SetFontQuality(FontQuality extraFontFlag) { void SurfaceD2D::SetFontQuality(FontQuality extraFontFlag) {
if (fontQuality != extraFontFlag) { if ((fontQuality != extraFontFlag) && renderingParams) {
fontQuality = extraFontFlag; fontQuality = extraFontFlag;
const D2D1_TEXT_ANTIALIAS_MODE aaMode = DWriteMapFontQuality(extraFontFlag); const D2D1_TEXT_ANTIALIAS_MODE aaMode = DWriteMapFontQuality(extraFontFlag);
if (aaMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE && renderingParams->customRenderingParams) {
if (aaMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE && customClearTypeRenderingParams) pRenderTarget->SetTextRenderingParams(renderingParams->customRenderingParams.get());
pRenderTarget->SetTextRenderingParams(customClearTypeRenderingParams); } else if (renderingParams->defaultRenderingParams) {
else if (defaultRenderingParams) pRenderTarget->SetTextRenderingParams(renderingParams->defaultRenderingParams.get());
pRenderTarget->SetTextRenderingParams(defaultRenderingParams); }
pRenderTarget->SetTextAntialiasMode(aaMode); pRenderTarget->SetTextAntialiasMode(aaMode);
} }
} }
@ -2642,6 +2615,10 @@ void SurfaceD2D::FlushDrawing() {
} }
} }
void SurfaceD2D::SetRenderingParams(std::shared_ptr<RenderingParams> renderingParams_) {
renderingParams = renderingParams_;
}
#endif #endif
std::unique_ptr<Surface> Surface::Allocate(Technology technology) { std::unique_ptr<Surface> Surface::Allocate(Technology technology) {
@ -3876,8 +3853,6 @@ void Platform_Initialise(void *hInstance) noexcept {
void Platform_Finalise(bool fromDllMain) noexcept { void Platform_Finalise(bool fromDllMain) noexcept {
#if defined(USE_D2D) #if defined(USE_D2D)
if (!fromDllMain) { if (!fromDllMain) {
ReleaseUnknown(defaultRenderingParams);
ReleaseUnknown(customClearTypeRenderingParams);
ReleaseUnknown(pIDWriteFactory); ReleaseUnknown(pIDWriteFactory);
ReleaseUnknown(pD2DFactory); ReleaseUnknown(pD2DFactory);
if (hDLLDWrite) { if (hDLLDWrite) {

View File

@ -53,6 +53,15 @@ HCURSOR LoadReverseArrowCursor(UINT dpi) noexcept;
extern bool LoadD2D(); extern bool LoadD2D();
extern ID2D1Factory *pD2DFactory; extern ID2D1Factory *pD2DFactory;
extern IDWriteFactory *pIDWriteFactory; extern IDWriteFactory *pIDWriteFactory;
struct RenderingParams {
std::unique_ptr<IDWriteRenderingParams, UnknownReleaser> defaultRenderingParams;
std::unique_ptr<IDWriteRenderingParams, UnknownReleaser> customRenderingParams;
};
struct ISetRenderingParams {
virtual void SetRenderingParams(std::shared_ptr<RenderingParams> renderingParams_) = 0;
};
#endif #endif
} }

View File

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

View File

@ -32,9 +32,9 @@
#define NOMINMAX #define NOMINMAX
#endif #endif
#undef _WIN32_WINNT #undef _WIN32_WINNT
#define _WIN32_WINNT 0x0500 #define _WIN32_WINNT 0x0A00
#undef WINVER #undef WINVER
#define WINVER 0x0500 #define WINVER 0x0A00
#define WIN32_LEAN_AND_MEAN 1 #define WIN32_LEAN_AND_MEAN 1
#include <windows.h> #include <windows.h>
#include <commctrl.h> #include <commctrl.h>
@ -147,12 +147,6 @@ constexpr int IndicatorTarget = IndicatorInput + 1;
constexpr int IndicatorConverted = IndicatorInput + 2; constexpr int IndicatorConverted = IndicatorInput + 2;
constexpr int IndicatorUnknown = IndicatorInput + 3; constexpr int IndicatorUnknown = IndicatorInput + 3;
#ifndef SCS_CAP_SETRECONVERTSTRING
#define SCS_CAP_SETRECONVERTSTRING 0x00000004
#define SCS_QUERYRECONVERTSTRING 0x00020000
#define SCS_SETRECONVERTSTRING 0x00010000
#endif
typedef UINT_PTR (WINAPI *SetCoalescableTimerSig)(HWND hwnd, UINT_PTR nIDEvent, typedef UINT_PTR (WINAPI *SetCoalescableTimerSig)(HWND hwnd, UINT_PTR nIDEvent,
UINT uElapse, TIMERPROC lpTimerFunc, ULONG uToleranceDelay); UINT uElapse, TIMERPROC lpTimerFunc, ULONG uToleranceDelay);
@ -356,6 +350,9 @@ class ScintillaWin :
#if defined(USE_D2D) #if defined(USE_D2D)
ID2D1RenderTarget *pRenderTarget; ID2D1RenderTarget *pRenderTarget;
bool renderTargetValid; bool renderTargetValid;
// rendering parameters for current monitor
HMONITOR hCurrentMonitor;
std::shared_ptr<RenderingParams> renderingParams;
#endif #endif
explicit ScintillaWin(HWND hwnd); explicit ScintillaWin(HWND hwnd);
@ -368,6 +365,7 @@ class ScintillaWin :
void Finalise() override; void Finalise() override;
#if defined(USE_D2D) #if defined(USE_D2D)
bool UpdateRenderingParams(bool force) noexcept;
void EnsureRenderTarget(HDC hdc); void EnsureRenderTarget(HDC hdc);
#endif #endif
void DropRenderTarget() noexcept; void DropRenderTarget() noexcept;
@ -392,6 +390,8 @@ class ScintillaWin :
Sci::Position TargetAsUTF8(char *text) const; Sci::Position TargetAsUTF8(char *text) const;
Sci::Position EncodedFromUTF8(const char *utf8, char *encoded) const; Sci::Position EncodedFromUTF8(const char *utf8, char *encoded) const;
void SetRenderingParams(Surface *psurf) const;
bool PaintDC(HDC hdc); bool PaintDC(HDC hdc);
sptr_t WndPaint(); sptr_t WndPaint();
@ -571,6 +571,7 @@ ScintillaWin::ScintillaWin(HWND hwnd) {
#if defined(USE_D2D) #if defined(USE_D2D)
pRenderTarget = nullptr; pRenderTarget = nullptr;
renderTargetValid = true; renderTargetValid = true;
hCurrentMonitor = {};
#endif #endif
caret.period = ::GetCaretBlinkTime(); caret.period = ::GetCaretBlinkTime();
@ -615,6 +616,38 @@ void ScintillaWin::Finalise() {
#if defined(USE_D2D) #if defined(USE_D2D)
bool ScintillaWin::UpdateRenderingParams(bool force) noexcept {
if (!renderingParams) {
renderingParams = std::make_shared<RenderingParams>();
}
HMONITOR monitor = ::MonitorFromWindow(MainHWND(), MONITOR_DEFAULTTONEAREST);
if (!force && monitor == hCurrentMonitor && renderingParams->defaultRenderingParams) {
return false;
}
IDWriteRenderingParams *monitorRenderingParams = nullptr;
IDWriteRenderingParams *customClearTypeRenderingParams = nullptr;
const HRESULT hr = pIDWriteFactory->CreateMonitorRenderingParams(monitor, &monitorRenderingParams);
UINT clearTypeContrast = 0;
if (SUCCEEDED(hr) && ::SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &clearTypeContrast, 0) != 0) {
if (clearTypeContrast >= 1000 && clearTypeContrast <= 2200) {
const FLOAT gamma = static_cast<FLOAT>(clearTypeContrast) / 1000.0f;
pIDWriteFactory->CreateCustomRenderingParams(gamma,
monitorRenderingParams->GetEnhancedContrast(),
monitorRenderingParams->GetClearTypeLevel(),
monitorRenderingParams->GetPixelGeometry(),
monitorRenderingParams->GetRenderingMode(),
&customClearTypeRenderingParams);
}
}
hCurrentMonitor = monitor;
renderingParams->defaultRenderingParams.reset(monitorRenderingParams);
renderingParams->customRenderingParams.reset(customClearTypeRenderingParams);
return true;
}
void ScintillaWin::EnsureRenderTarget(HDC hdc) { void ScintillaWin::EnsureRenderTarget(HDC hdc) {
if (!renderTargetValid) { if (!renderTargetValid) {
DropRenderTarget(); DropRenderTarget();
@ -684,7 +717,6 @@ void ScintillaWin::EnsureRenderTarget(HDC hdc) {
} }
#endif #endif
void ScintillaWin::DropRenderTarget() noexcept { void ScintillaWin::DropRenderTarget() noexcept {
#if defined(USE_D2D) #if defined(USE_D2D)
ReleaseUnknown(pRenderTarget); ReleaseUnknown(pRenderTarget);
@ -911,6 +943,17 @@ Sci::Position ScintillaWin::EncodedFromUTF8(const char *utf8, char *encoded) con
} }
} }
void ScintillaWin::SetRenderingParams([[maybe_unused]] Surface *psurf) const {
#if defined(USE_D2D)
if (psurf) {
ISetRenderingParams *setDrawingParams = dynamic_cast<ISetRenderingParams *>(psurf);
if (setDrawingParams) {
setDrawingParams->SetRenderingParams(renderingParams);
}
}
#endif
}
bool ScintillaWin::PaintDC(HDC hdc) { bool ScintillaWin::PaintDC(HDC hdc) {
if (technology == Technology::Default) { if (technology == Technology::Default) {
AutoSurface surfaceWindow(hdc, this); AutoSurface surfaceWindow(hdc, this);
@ -924,6 +967,7 @@ bool ScintillaWin::PaintDC(HDC hdc) {
if (pRenderTarget) { if (pRenderTarget) {
AutoSurface surfaceWindow(pRenderTarget, this); AutoSurface surfaceWindow(pRenderTarget, this);
if (surfaceWindow) { if (surfaceWindow) {
SetRenderingParams(surfaceWindow);
pRenderTarget->BeginDraw(); pRenderTarget->BeginDraw();
Paint(surfaceWindow, rcPaint); Paint(surfaceWindow, rcPaint);
surfaceWindow->Release(); surfaceWindow->Release();
@ -1887,9 +1931,11 @@ sptr_t ScintillaWin::SciMessage(Message iMessage, uptr_t wParam, sptr_t lParam)
if (technology != technologyNew) { if (technology != technologyNew) {
if (technologyNew > Technology::Default) { if (technologyNew > Technology::Default) {
#if defined(USE_D2D) #if defined(USE_D2D)
if (!LoadD2D()) if (!LoadD2D()) {
// Failed to load Direct2D or DirectWrite so no effect // Failed to load Direct2D or DirectWrite so no effect
return 0; return 0;
}
UpdateRenderingParams(true);
#else #else
return 0; return 0;
#endif #endif
@ -1900,7 +1946,6 @@ sptr_t ScintillaWin::SciMessage(Message iMessage, uptr_t wParam, sptr_t lParam)
technology = technologyNew; technology = technologyNew;
view.bufferedDraw = technologyNew == Technology::Default; view.bufferedDraw = technologyNew == Technology::Default;
// Invalidate all cached information including layout. // Invalidate all cached information including layout.
DropGraphics();
InvalidateStyleRedraw(); InvalidateStyleRedraw();
} }
} }
@ -1913,7 +1958,6 @@ sptr_t ScintillaWin::SciMessage(Message iMessage, uptr_t wParam, sptr_t lParam)
bidirectional = static_cast<Bidirectional>(wParam); bidirectional = static_cast<Bidirectional>(wParam);
} }
// Invalidate all cached information including layout. // Invalidate all cached information including layout.
DropGraphics();
InvalidateStyleRedraw(); InvalidateStyleRedraw();
break; break;
@ -2017,10 +2061,15 @@ sptr_t ScintillaWin::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
case WM_SETTINGCHANGE: case WM_SETTINGCHANGE:
//Platform::DebugPrintf("Setting Changed\n"); //Platform::DebugPrintf("Setting Changed\n");
#if defined(USE_D2D)
if (technology != Technology::Default) {
UpdateRenderingParams(true);
}
#endif
UpdateBaseElements(); UpdateBaseElements();
InvalidateStyleData();
// Get Intellimouse scroll line parameters // Get Intellimouse scroll line parameters
GetIntelliMouseParameters(); GetIntelliMouseParameters();
InvalidateStyleRedraw();
break; break;
case WM_GETDLGCODE: case WM_GETDLGCODE:
@ -2081,7 +2130,17 @@ sptr_t ScintillaWin::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
case WM_NCLBUTTONDOWN: case WM_NCLBUTTONDOWN:
case WM_SYSCOMMAND: case WM_SYSCOMMAND:
case WM_WINDOWPOSCHANGING: case WM_WINDOWPOSCHANGING:
return ::DefWindowProc(MainHWND(), msg, wParam, lParam);
case WM_WINDOWPOSCHANGED: case WM_WINDOWPOSCHANGED:
#if defined(USE_D2D)
if (technology != Technology::Default) {
if (UpdateRenderingParams(false)) {
DropGraphics();
Redraw();
}
}
#endif
return ::DefWindowProc(MainHWND(), msg, wParam, lParam); return ::DefWindowProc(MainHWND(), msg, wParam, lParam);
case WM_GETTEXTLENGTH: case WM_GETTEXTLENGTH:
@ -3562,11 +3621,11 @@ LRESULT PASCAL ScintillaWin::CTWndProc(
#endif #endif
RECT rc; RECT rc;
GetClientRect(hWnd, &rc); GetClientRect(hWnd, &rc);
// Create a Direct2D render target.
if (sciThis->technology == Technology::Default) { if (sciThis->technology == Technology::Default) {
surfaceWindow->Init(ps.hdc, hWnd); surfaceWindow->Init(ps.hdc, hWnd);
} else { } else {
#if defined(USE_D2D) #if defined(USE_D2D)
// Create a Direct2D render target.
D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp {}; D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp {};
dhrtp.hwnd = hWnd; dhrtp.hwnd = hWnd;
dhrtp.pixelSize = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top); dhrtp.pixelSize = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
@ -3595,7 +3654,8 @@ LRESULT PASCAL ScintillaWin::CTWndProc(
} }
#endif #endif
} }
surfaceWindow->SetMode(SurfaceMode(sciThis->ct.codePage, sciThis->BidirectionalR2L())); surfaceWindow->SetMode(sciThis->CurrentSurfaceMode());
sciThis->SetRenderingParams(surfaceWindow.get());
sciThis->ct.PaintCT(surfaceWindow.get()); sciThis->ct.PaintCT(surfaceWindow.get());
#if defined(USE_D2D) #if defined(USE_D2D)
if (pCTRenderTarget) if (pCTRenderTarget)

View File

@ -21,7 +21,7 @@ LD=link
!IFDEF SUPPORT_XP !IFDEF SUPPORT_XP
ADD_DEFINE=-D_USING_V110_SDK71_ ADD_DEFINE=-D_USING_V110_SDK71_
# Different subsystems for 32-bit and 64-bit Windows XP so detect based on Platform # 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" !IF "$(PLATFORM)" == "x64"
SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.02 SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.02
!ELSE !ELSE