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:
parent
3b0d5242ac
commit
100d45f7cf
Binary file not shown.
Binary file not shown.
|
@ -19,6 +19,7 @@
|
|||
**.def text
|
||||
**.manifest text
|
||||
**.properties text
|
||||
**.session text
|
||||
**.styled text
|
||||
**.folded text
|
||||
**.adoc text
|
||||
|
|
|
@ -55,7 +55,7 @@ std::wstring WideStringFromUTF8(std::string_view sv) {
|
|||
const int sLength = static_cast<int>(sv.length());
|
||||
const int cchWide = ::MultiByteToWideChar(CP_UTF8, 0, sv.data(), sLength, nullptr, 0);
|
||||
std::wstring sWide(cchWide, 0);
|
||||
::MultiByteToWideChar(CP_UTF8, 0, sv.data(), sLength, &sWide[0], cchWide);
|
||||
::MultiByteToWideChar(CP_UTF8, 0, sv.data(), sLength, sWide.data(), cchWide);
|
||||
return sWide;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" />
|
||||
<meta name="Description"
|
||||
content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." />
|
||||
<meta name="Date.Modified" content="20220209" />
|
||||
<meta name="Date.Modified" content="20220331" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style type="text/css">
|
||||
.logo {
|
||||
|
@ -61,8 +61,8 @@
|
|||
<font color="#FFCC99" size="4"> A library of language lexers for use with Scintilla</font>
|
||||
</td>
|
||||
<td width="40%" align="right">
|
||||
<font color="#FFCC99" size="3">Release version 5.1.5<br />
|
||||
Site last modified February 9 2022</font>
|
||||
<font color="#FFCC99" size="3">Release version 5.1.6<br />
|
||||
Site last modified March 31 2022</font>
|
||||
</td>
|
||||
<td width="20%">
|
||||
|
||||
|
@ -77,6 +77,7 @@
|
|||
</tr>
|
||||
</table>
|
||||
<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.4 adds lexers for AsciiDoc and GDScript.</li>
|
||||
<li>Version 5.1.3 improves Rust.</li>
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<font size="4"> <a href="https://www.scintilla.org/lexilla515.zip">
|
||||
<font size="4"> <a href="https://www.scintilla.org/lexilla516.zip">
|
||||
Windows</a>
|
||||
<a href="https://www.scintilla.org/lexilla515.tgz">
|
||||
<a href="https://www.scintilla.org/lexilla516.tgz">
|
||||
GTK/Linux</a>
|
||||
</font>
|
||||
</td>
|
||||
|
@ -42,7 +42,7 @@
|
|||
containing very few restrictions.
|
||||
</p>
|
||||
<h3>
|
||||
Release 5.1.5
|
||||
Release 5.1.6
|
||||
</h3>
|
||||
<h4>
|
||||
Source Code
|
||||
|
@ -50,8 +50,8 @@
|
|||
The source code package contains all of the source code for Lexilla but no binary
|
||||
executable code and is available in
|
||||
<ul>
|
||||
<li><a href="https://www.scintilla.org/lexilla515.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.zip">zip format</a> (1.1M) commonly used on Windows</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>
|
||||
Instructions for building on both Windows and Linux are included in the readme file.
|
||||
<h4>
|
||||
|
|
|
@ -577,6 +577,7 @@
|
|||
<td>Arkadiusz Michalski</td>
|
||||
</tr><tr>
|
||||
<td>Red_M</td>
|
||||
<td>cdbdev</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2>Releases</h2>
|
||||
|
@ -585,13 +586,49 @@
|
|||
</h3>
|
||||
<ul>
|
||||
<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>
|
||||
Add LexAccessor::BufferStyleAt to retrieve style values to simplify logic and
|
||||
improve performance.
|
||||
<a href="https://github.com/ScintillaOrg/lexilla/issues/54">Issue #54</a>.
|
||||
</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>
|
||||
<h3>
|
||||
<a href="https://www.scintilla.org/lexilla515.zip">Release 5.1.5</a>
|
||||
|
|
|
@ -66,6 +66,7 @@ constexpr bool IsNewline(const int ch) {
|
|||
}
|
||||
|
||||
// True if can follow ch down to the end with possibly trailing whitespace
|
||||
// Does not set the state SCE_MARKDOWN_LINE_BEGIN as to allow further processing
|
||||
static bool FollowToLineEnd(const int ch, const int state, const Sci_PositionU endPos, StyleContext &sc) {
|
||||
Sci_Position i = 0;
|
||||
while (sc.GetRelative(++i) == ch)
|
||||
|
@ -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)
|
||||
++i;
|
||||
if (IsNewline(sc.GetRelative(i)) || sc.currentPos + i == endPos) {
|
||||
sc.SetState(state);
|
||||
sc.Forward(i);
|
||||
sc.ChangeState(state);
|
||||
sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
|
@ -176,6 +176,10 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
|
|||
// in the default state.
|
||||
bool freezeCursor = false;
|
||||
|
||||
// property lexer.markdown.header.eolfill
|
||||
// Set to 1 to highlight all ATX header text.
|
||||
bool headerEOLFill = styler.GetPropertyInt("lexer.markdown.header.eolfill", 0) == 1;
|
||||
|
||||
StyleContext sc(startPos, static_cast<Sci_PositionU>(length), initStyle, styler);
|
||||
|
||||
while (sc.More()) {
|
||||
|
@ -265,22 +269,45 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
|
|||
}
|
||||
else if (sc.state == SCE_MARKDOWN_LINE_BEGIN) {
|
||||
// Header
|
||||
if (sc.Match("######"))
|
||||
if (sc.Match("######")) {
|
||||
if (headerEOLFill)
|
||||
sc.SetState(SCE_MARKDOWN_HEADER6);
|
||||
else
|
||||
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);
|
||||
else if (sc.Match("####"))
|
||||
}
|
||||
else if (sc.Match("####")) {
|
||||
if (headerEOLFill)
|
||||
sc.SetState(SCE_MARKDOWN_HEADER4);
|
||||
else
|
||||
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);
|
||||
else if (sc.Match("##"))
|
||||
}
|
||||
else if (sc.Match("##")) {
|
||||
if (headerEOLFill)
|
||||
sc.SetState(SCE_MARKDOWN_HEADER2);
|
||||
else
|
||||
SetStateAndZoom(SCE_MARKDOWN_HEADER2, 2, '#', sc);
|
||||
}
|
||||
else if (sc.Match("#")) {
|
||||
// Catch the special case of an unordered list
|
||||
if (sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) {
|
||||
precharCount = 0;
|
||||
sc.SetState(SCE_MARKDOWN_PRECHAR);
|
||||
}
|
||||
else if (headerEOLFill) {
|
||||
sc.SetState(SCE_MARKDOWN_HEADER1);
|
||||
}
|
||||
else
|
||||
SetStateAndZoom(SCE_MARKDOWN_HEADER1, 1, '#', sc);
|
||||
}
|
||||
|
@ -292,14 +319,18 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
|
|||
sc.SetState(SCE_MARKDOWN_DEFAULT);
|
||||
}
|
||||
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
|
||||
sc.SetState(SCE_MARKDOWN_DEFAULT);
|
||||
}
|
||||
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 {
|
||||
precharCount = 0;
|
||||
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 ||
|
||||
sc.state == SCE_MARKDOWN_HEADER3 || sc.state == SCE_MARKDOWN_HEADER4 ||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -420,7 +457,8 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
|
|||
// Emphasis
|
||||
else if (sc.ch == '*' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "*")) {
|
||||
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);
|
||||
}
|
||||
// Strikeout
|
||||
|
|
|
@ -102,7 +102,7 @@ static bool keywordIsModifier(const char *word,
|
|||
Sci_Position pos,
|
||||
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];
|
||||
Sci_PositionU i, j;
|
||||
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] = '\0';
|
||||
int chAttr;
|
||||
int chAttr = SCE_RB_IDENTIFIER;
|
||||
int style = SCE_RB_DEFAULT;
|
||||
if (0 == strcmp(prevWord, "class"))
|
||||
chAttr = SCE_RB_CLASSNAME;
|
||||
else if (0 == strcmp(prevWord, "module"))
|
||||
chAttr = SCE_RB_MODULE_NAME;
|
||||
else if (0 == strcmp(prevWord, "def"))
|
||||
else if (0 == strcmp(prevWord, "def")) {
|
||||
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))) {
|
||||
if (keywordIsAmbiguous(s)
|
||||
&& keywordIsModifier(s, start, styler)) {
|
||||
|
@ -136,15 +145,15 @@ static int ClassifyWordRb(Sci_PositionU start, Sci_PositionU end, WordList &keyw
|
|||
chAttr = SCE_RB_WORD_DEMOTED;
|
||||
} else {
|
||||
chAttr = SCE_RB_WORD;
|
||||
}
|
||||
} else
|
||||
chAttr = SCE_RB_IDENTIFIER;
|
||||
styler.ColourTo(end, chAttr);
|
||||
if (chAttr == SCE_RB_WORD) {
|
||||
style = SCE_RB_WORD;
|
||||
strcpy(prevWord, s);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
if (style == SCE_RB_DEFAULT) {
|
||||
style = chAttr;
|
||||
prevWord[0] = 0;
|
||||
}
|
||||
styler.ColourTo(end, style);
|
||||
return chAttr;
|
||||
}
|
||||
|
||||
|
@ -461,7 +470,6 @@ static Sci_Position findExpressionStart(Sci_Position pos,
|
|||
|
||||
static bool sureThisIsNotHeredoc(Sci_Position lt2StartPos,
|
||||
Accessor &styler) {
|
||||
int prevStyle;
|
||||
// Use full document, not just part we're styling
|
||||
Sci_Position lengthDoc = styler.Length();
|
||||
Sci_Position lineStart = styler.GetLine(lt2StartPos);
|
||||
|
@ -478,9 +486,10 @@ static bool sureThisIsNotHeredoc(Sci_Position lt2StartPos,
|
|||
if (firstWordPosn >= lt2StartPos) {
|
||||
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 (prevStyle != SCE_RB_IDENTIFIER
|
||||
&& prevStyle != SCE_RB_GLOBAL // $stdout and $stderr
|
||||
&& prevStyle != SCE_RB_SYMBOL
|
||||
&& prevStyle != SCE_RB_INSTANCE_VAR
|
||||
&& prevStyle != SCE_RB_CLASS_VAR) {
|
||||
|
@ -595,7 +604,7 @@ static bool sureThisIsNotHeredoc(Sci_Position lt2StartPos,
|
|||
return definitely_not_a_here_doc;
|
||||
} else {
|
||||
char ch = styler[j];
|
||||
if (ch == '#' || isEOLChar(ch)) {
|
||||
if (ch == '#' || isEOLChar(ch) || ch == '.' || ch == ',') {
|
||||
// This is OK, so break and continue;
|
||||
break;
|
||||
} else {
|
||||
|
@ -714,6 +723,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
|
|||
false);
|
||||
|
||||
bool preferRE = true;
|
||||
bool afterDef = false;
|
||||
int state = initStyle;
|
||||
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)) {
|
||||
// Begin of here-doc (the line after the here-doc delimiter):
|
||||
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
|
||||
// the here-doc state
|
||||
state = SCE_RB_HERE_Q;
|
||||
|
@ -862,7 +877,10 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
|
|||
Quote.New();
|
||||
Quote.Open(ch);
|
||||
} else if (ch == '<' && chNext == '<' && chNext2 != '=') {
|
||||
|
||||
if (afterDef) {
|
||||
afterDef = false;
|
||||
prevWord[0] = 0;
|
||||
}
|
||||
// Recognise the '<<' symbol - either a here document or a binary op
|
||||
styler.ColourTo(i - 1, state);
|
||||
i++;
|
||||
|
@ -893,6 +911,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
|
|||
}
|
||||
preferRE = (state != SCE_RB_HERE_DELIM);
|
||||
} else if (ch == ':') {
|
||||
afterDef = false;
|
||||
styler.ColourTo(i - 1, state);
|
||||
if (chNext == ':') {
|
||||
// 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;
|
||||
preferRE = true;
|
||||
}
|
||||
} else if (ch == '%') {
|
||||
} else if (ch == '%' && !afterDef) {
|
||||
styler.ColourTo(i - 1, state);
|
||||
bool have_string = false;
|
||||
if (strchr(q_chars, chNext) && !isSafeWordcharOrHigh(chNext2)) {
|
||||
|
@ -1046,6 +1065,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
|
|||
preferRE = true;
|
||||
}
|
||||
} else if (ch == '?') {
|
||||
afterDef = false;
|
||||
styler.ColourTo(i - 1, state);
|
||||
if (iswhitespace(chNext) || chNext == '\n' || chNext == '\r') {
|
||||
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 == '.') {
|
||||
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);
|
||||
// If we're ending an expression or block,
|
||||
// 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
|
||||
} else if (isEOLChar(ch)) {
|
||||
afterDef = false;
|
||||
// Make sure it's a true line-end, with no backslash
|
||||
if ((ch == '\r' || (ch == '\n' && chPrev != '\r'))
|
||||
&& chPrev != '\\') {
|
||||
|
@ -1089,6 +1120,9 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
|
|||
preferRE = true;
|
||||
}
|
||||
}
|
||||
if (afterDef && state != SCE_RB_DEFAULT) {
|
||||
afterDef = false;
|
||||
}
|
||||
} else if (state == SCE_RB_WORD) {
|
||||
if (ch == '.' || !isSafeWordcharOrHigh(ch)) {
|
||||
// Words include x? in all contexts,
|
||||
|
@ -1127,9 +1161,10 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
|
|||
preferRE = false;
|
||||
} else {
|
||||
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) {
|
||||
case SCE_RB_WORD:
|
||||
afterDef = strcmp(prevWord, "def") == 0;
|
||||
preferRE = RE_CanFollowKeyword(prevWord);
|
||||
break;
|
||||
|
||||
|
@ -1152,6 +1187,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
|
|||
if (ch == '.') {
|
||||
// We might be redefining an operator-method
|
||||
preferRE = false;
|
||||
afterDef = word_style == SCE_RB_DEFNAME;
|
||||
}
|
||||
// And if it's the first
|
||||
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,
|
||||
lengthDoc,
|
||||
HereDoc.Delimiter)) {
|
||||
styler.ColourTo(i - 1 - HereDoc.DelimiterLength, state);
|
||||
styler.ColourTo(i - HereDoc.DelimiterLength, state);
|
||||
styler.ColourTo(i, SCE_RB_HERE_DELIM);
|
||||
state = SCE_RB_DEFAULT;
|
||||
preferRE = false;
|
||||
|
@ -1459,7 +1495,7 @@ static void ColouriseRbDoc(Sci_PositionU startPos, Sci_Position length, int init
|
|||
if (state == SCE_RB_WORD) {
|
||||
// We've ended on a word, possibly at EOF, and need to
|
||||
// classify it.
|
||||
(void) ClassifyWordRb(styler.GetStartSegment(), lengthDoc - 1, keywords, styler, prevWord);
|
||||
(void) ClassifyWordRb(styler.GetStartSegment(), lengthDoc - 1, '\0', keywords, styler, prevWord);
|
||||
} else {
|
||||
styler.ColourTo(lengthDoc - 1, state);
|
||||
}
|
||||
|
@ -1754,10 +1790,21 @@ static void FoldRbDoc(Sci_PositionU startPos, Sci_Position length, int initStyle
|
|||
& SC_FOLDLEVELNUMBERMASK
|
||||
& ~SC_FOLDLEVELBASE);
|
||||
int levelCurrent = levelPrev;
|
||||
char chPrev = '\0';
|
||||
char chNext = styler[startPos];
|
||||
int styleNext = styler.StyleAt(startPos);
|
||||
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++) {
|
||||
char ch = chNext;
|
||||
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
|
||||
if (levelCurrent > 0)
|
||||
levelCurrent--;
|
||||
} else if (!strcmp(prevWord, "def")) {
|
||||
levelCurrent++;
|
||||
method_definition = MethodDefinition::Define;
|
||||
} else if (!strcmp(prevWord, "if")
|
||||
|| !strcmp(prevWord, "def")
|
||||
|| !strcmp(prevWord, "class")
|
||||
|| !strcmp(prevWord, "module")
|
||||
|| !strcmp(prevWord, "begin")
|
||||
|
@ -1820,8 +1869,64 @@ static void FoldRbDoc(Sci_PositionU startPos, Sci_Position length, int initStyle
|
|||
} else if (styleNext == SCE_RB_DEFAULT) {
|
||||
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;
|
||||
if (visibleChars == 0 && foldCompact)
|
||||
lev |= SC_FOLDLEVELWHITEFLAG;
|
||||
|
@ -1831,23 +1936,14 @@ static void FoldRbDoc(Sci_PositionU startPos, Sci_Position length, int initStyle
|
|||
lineCurrent++;
|
||||
levelPrev = levelCurrent;
|
||||
visibleChars = 0;
|
||||
buffer_ends_with_eol = true;
|
||||
method_definition = MethodDefinition::None;
|
||||
argument_paren_count = 0;
|
||||
} else if (!isspacechar(ch)) {
|
||||
visibleChars++;
|
||||
buffer_ends_with_eol = false;
|
||||
}
|
||||
chPrev = ch;
|
||||
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[] = {
|
||||
|
|
|
@ -122,12 +122,12 @@ public:
|
|||
}
|
||||
// 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.
|
||||
char BufferStyleAt(Sci_Position position) const {
|
||||
int BufferStyleAt(Sci_Position position) const {
|
||||
const Sci_Position index = position - startPosStyling;
|
||||
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 {
|
||||
return pAccess->LineFromPosition(position);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
// This file is in the public domain.
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
#include <string>
|
||||
|
@ -20,6 +21,33 @@
|
|||
|
||||
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) {
|
||||
if (MakeLowerCase(ch) != static_cast<unsigned char>(*s))
|
||||
return false;
|
||||
|
@ -54,19 +82,6 @@ bool StyleContext::MatchIgnoreCase2(const char *s) {
|
|||
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) {
|
||||
styler.GetRange(styler.GetStartSegment(), currentPos, s, len);
|
||||
}
|
||||
|
|
|
@ -16,21 +16,21 @@ namespace Lexilla {
|
|||
// syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80
|
||||
class StyleContext {
|
||||
LexAccessor &styler;
|
||||
Scintilla::IDocument *multiByteAccess;
|
||||
Sci_PositionU endPos;
|
||||
Sci_PositionU lengthDocument;
|
||||
Scintilla::IDocument * const multiByteAccess;
|
||||
const Sci_PositionU lengthDocument;
|
||||
const Sci_PositionU endPos;
|
||||
const Sci_Position lineDocEnd;
|
||||
|
||||
// Used for optimizing GetRelativeCharacter
|
||||
Sci_PositionU posRelative;
|
||||
Sci_PositionU posRelative = 0;
|
||||
Sci_PositionU currentPosLastRelative;
|
||||
Sci_Position offsetRelative;
|
||||
Sci_Position offsetRelative = 0;
|
||||
|
||||
void GetNextChar() {
|
||||
if (multiByteAccess) {
|
||||
chNext = multiByteAccess->GetCharacterAndWidth(currentPos+width, &widthNext);
|
||||
} else {
|
||||
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+width, 0));
|
||||
widthNext = 1;
|
||||
}
|
||||
// End of line determined from line end position, allowing CR, LF,
|
||||
// CRLF and Unicode line ends as set by document.
|
||||
|
@ -43,59 +43,19 @@ class StyleContext {
|
|||
public:
|
||||
Sci_PositionU currentPos;
|
||||
Sci_Position currentLine;
|
||||
Sci_Position lineDocEnd;
|
||||
Sci_Position lineEnd;
|
||||
Sci_Position lineStartNext;
|
||||
bool atLineStart;
|
||||
bool atLineEnd;
|
||||
bool atLineEnd = false;
|
||||
int state;
|
||||
int chPrev;
|
||||
int ch;
|
||||
Sci_Position width;
|
||||
int chNext;
|
||||
Sci_Position widthNext;
|
||||
int chPrev = 0;
|
||||
int ch = 0;
|
||||
Sci_Position width = 0;
|
||||
int chNext = 0;
|
||||
Sci_Position widthNext = 1;
|
||||
|
||||
StyleContext(Sci_PositionU startPos, Sci_PositionU length,
|
||||
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();
|
||||
}
|
||||
int initStyle, LexAccessor &styler_, char chMask = '\377');
|
||||
// Deleted so StyleContext objects can not be copied.
|
||||
StyleContext(const StyleContext &) = delete;
|
||||
StyleContext &operator=(const StyleContext &) = delete;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
// C++ wrappers of C standard library
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
rem Test lexers
|
||||
rem build lexilla.dll and TestLexers.exe then run TestLexers.exe
|
||||
cd ../src
|
||||
make DEBUG=1
|
||||
make --jobs=4 DEBUG=1
|
||||
cd ../test
|
||||
make DEBUG=1
|
||||
make test
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
# Test lexers
|
||||
# build lexilla.so and TestLexers then run TestLexers
|
||||
JOBS="--jobs=$(getconf _NPROCESSORS_ONLN)"
|
||||
(
|
||||
cd ../src
|
||||
make DEBUG=1
|
||||
make "$JOBS" DEBUG=1
|
||||
)
|
||||
(
|
||||
cd ../test
|
||||
make DEBUG=1
|
||||
make test
|
||||
)
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.1.5</string>
|
||||
<string>5.1.6</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
|
|
@ -851,7 +851,7 @@
|
|||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 5.1.5;
|
||||
CURRENT_PROJECT_VERSION = 5.1.6;
|
||||
DEVELOPMENT_TEAM = 4F446KW87E;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
|
@ -877,7 +877,7 @@
|
|||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 5.1.5;
|
||||
CURRENT_PROJECT_VERSION = 5.1.6;
|
||||
DEVELOPMENT_TEAM = 4F446KW87E;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
|
|
|
@ -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>
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#include <windows.h>
|
||||
|
||||
#define VERSION_LEXILLA "5.1.5"
|
||||
#define VERSION_WORDS 5, 1, 5, 0
|
||||
#define VERSION_LEXILLA "5.1.6"
|
||||
#define VERSION_WORDS 5, 1, 6, 0
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION_WORDS
|
||||
|
|
|
@ -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.
|
||||
|
||||
If there is a need to test additional configurations of keywords or properties then
|
||||
create another subdirectory with the different settings in a new SciTE.properties.
|
||||
Properties can be set for a particular file with an "if $(=" or "match" expression like so:
|
||||
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
|
||||
testlexers.repeat.lex and testlexers.repeat.fold specify the number of times example
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace {
|
|||
};
|
||||
|
||||
int UnicodeFromUTF8(const unsigned char *us) noexcept {
|
||||
assert(us);
|
||||
switch (UTF8BytesOfLead[us[0]]) {
|
||||
case 1:
|
||||
return us[0];
|
||||
|
@ -56,6 +57,56 @@ namespace {
|
|||
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) {
|
||||
|
@ -65,7 +116,7 @@ void TestDocument::Set(std::string_view sv) {
|
|||
endStyled = 0;
|
||||
lineStarts.push_back(0);
|
||||
for (size_t pos = 0; pos < text.length(); pos++) {
|
||||
if (text[pos] == '\n') {
|
||||
if (text.at(pos) == '\n') {
|
||||
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) {
|
||||
for (Sci_Position i = 0; i < length; i++) {
|
||||
textStyles[endStyled] = style;
|
||||
textStyles.at(endStyled) = style;
|
||||
endStyled++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SCI_METHOD TestDocument::SetStyles(Sci_Position length, const char *styles) {
|
||||
assert(styles);
|
||||
for (Sci_Position i = 0; i < length; i++) {
|
||||
textStyles[endStyled] = styles[i];
|
||||
textStyles.at(endStyled) = styles[i];
|
||||
endStyled++;
|
||||
}
|
||||
return true;
|
||||
|
@ -252,8 +304,9 @@ int SCI_METHOD TestDocument::GetCharacterAndWidth(Sci_Position position, Sci_Pos
|
|||
}
|
||||
const int widthCharBytes = UTF8BytesOfLead[leadByte];
|
||||
unsigned char charBytes[] = { leadByte,0,0,0 };
|
||||
for (int b = 1; b < widthCharBytes; b++)
|
||||
charBytes[b] = text[position + b];
|
||||
for (int b = 1; b < widthCharBytes; b++) {
|
||||
charBytes[b] = text.at(position + b);
|
||||
}
|
||||
|
||||
if (pWidth) {
|
||||
*pWidth = widthCharBytes;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#ifndef TESTDOCUMENT_H
|
||||
#define TESTDOCUMENT_H
|
||||
|
||||
std::u32string UTF32FromUTF8(std::string_view svu8);
|
||||
|
||||
class TestDocument : public Scintilla::IDocument {
|
||||
std::string text;
|
||||
std::string textStyles;
|
||||
|
|
|
@ -29,9 +29,233 @@
|
|||
|
||||
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 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::ifstream ifs(path, std::ios::binary);
|
||||
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) {
|
||||
assert(pdoc);
|
||||
std::ostringstream os(std::ios::binary);
|
||||
char prevStyle = -1;
|
||||
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) {
|
||||
assert(pdoc);
|
||||
std::ostringstream os(std::ios::binary);
|
||||
Sci_Position linePrev = -1;
|
||||
char ch = '\0';
|
||||
|
@ -94,12 +320,115 @@ std::pair<std::string, std::string> MarkedAndFoldedDocument(const Scintilla::IDo
|
|||
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 {
|
||||
|
||||
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:
|
||||
using PropMap = std::map<std::string, std::string>;
|
||||
PropMap properties;
|
||||
|
||||
void ReadFromFile(std::filesystem::path path) {
|
||||
bool ifIsTrue = true;
|
||||
std::ifstream ifs(path);
|
||||
std::string line;
|
||||
std::string logicalLine;
|
||||
|
@ -112,12 +441,7 @@ public:
|
|||
if (logicalLine.ends_with("\\")) {
|
||||
logicalLine.pop_back();
|
||||
} else {
|
||||
const size_t positionEquals = logicalLine.find("=");
|
||||
if (positionEquals != std::string::npos) {
|
||||
const std::string key = logicalLine.substr(0, positionEquals);
|
||||
const std::string value = logicalLine.substr(positionEquals + 1);
|
||||
properties[key] = value;
|
||||
}
|
||||
ifIsTrue = ProcessLine(logicalLine, ifIsTrue);
|
||||
logicalLine.clear();
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +495,8 @@ bool CheckSame(std::string_view augmentedText, std::string_view augmentedTextNew
|
|||
}
|
||||
const size_t lineNumber = FirstLineDifferent(augmentedText, augmentedTextNew) + 1;
|
||||
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;
|
||||
pathNew += suffix;
|
||||
pathNew += ".new";
|
||||
|
@ -204,6 +529,7 @@ int UnixToWindows(std::string &s) {
|
|||
const std::string BOM = "\xEF\xBB\xBF";
|
||||
|
||||
void StyleLineByLine(TestDocument &doc, Scintilla::ILexer5 *plex) {
|
||||
assert(plex);
|
||||
Scintilla::IDocument *pdoc = &doc;
|
||||
const Sci_Position lines = doc.LineFromPosition(doc.Length());
|
||||
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
|
||||
// it difficult to test on different platforms when files may have line ends changed.
|
||||
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 << ":" <<
|
||||
" different styles between \\r and \\n at " <<
|
||||
pos << ": " << prevStyle << ", " << styleNow << "\n";
|
||||
success = false;
|
||||
}
|
||||
line++;
|
||||
}
|
||||
|
@ -265,9 +593,11 @@ void TestCRLF(std::filesystem::path path, const std::string s, Scintilla::ILexer
|
|||
|
||||
if (styledText != styledTextUnix) {
|
||||
std::cout << "\n" << path.string() << ":1: has different styles with \\n versus \\r\\n line ends\n\n";
|
||||
success = false;
|
||||
}
|
||||
if (foldedText != foldedTextUnix) {
|
||||
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
|
||||
|
@ -277,14 +607,21 @@ void TestCRLF(std::filesystem::path path, const std::string s, Scintilla::ILexer
|
|||
// Convert results from \n to \r\n run
|
||||
UnixToWindows(styledTextNewPerLine);
|
||||
UnixToWindows(foldedTextNewPerLine);
|
||||
CheckSame(styledTextUnix, styledTextNewPerLine, "per-line styles \\n", suffixStyled, path);
|
||||
CheckSame(foldedTextUnix, foldedTextNewPerLine, "per-line folds \\n", suffixFolded, path);
|
||||
if (!CheckSame(styledTextUnix, styledTextNewPerLine, "per-line styles \\n", suffixStyled, path)) {
|
||||
success = false;
|
||||
}
|
||||
if (!CheckSame(foldedTextUnix, foldedTextNewPerLine, "per-line folds \\n", suffixFolded, path)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
plex->Release();
|
||||
return success;
|
||||
}
|
||||
|
||||
void TestILexer(Scintilla::ILexer5 *plex) {
|
||||
assert(plex);
|
||||
|
||||
// Test each method of the ILexer interface.
|
||||
// Mostly ensures there are no crashes when calling methods.
|
||||
// Some methods are tested later (Release, Lex, Fold).
|
||||
|
@ -320,11 +657,11 @@ void TestILexer(Scintilla::ILexer5 *plex) {
|
|||
[[maybe_unused]] const int lineEndTypes = plex->LineEndTypesSupported();
|
||||
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
|
||||
while (*bases) {
|
||||
while (!bases.empty()) {
|
||||
constexpr int newStyles = 3;
|
||||
const int base = *bases;
|
||||
const int base = bases.front();
|
||||
const int baseStyle = plex->AllocateSubStyles(base, newStyles);
|
||||
[[maybe_unused]] const int styleBack = plex->StyleFromSubStyle(baseStyle);
|
||||
assert(styleBack == base);
|
||||
|
@ -333,7 +670,7 @@ void TestILexer(Scintilla::ILexer5 *plex) {
|
|||
assert(start == baseStyle);
|
||||
[[maybe_unused]] const int len = plex->SubStylesLength(base);
|
||||
assert(len == newStyles);
|
||||
bases++;
|
||||
bases.remove_prefix(1);
|
||||
}
|
||||
plex->FreeSubStyles();
|
||||
}
|
||||
|
@ -359,6 +696,8 @@ void TestILexer(Scintilla::ILexer5 *plex) {
|
|||
}
|
||||
|
||||
void SetProperties(Scintilla::ILexer5 *plex, const PropertyMap &propertyMap, std::string_view fileName) {
|
||||
assert(plex);
|
||||
|
||||
// Set keywords, keywords2, ... keywords9, for this file
|
||||
for (int kw = 0; kw < 10; kw++) {
|
||||
std::string kwChoice("keywords");
|
||||
|
@ -374,9 +713,7 @@ void SetProperties(Scintilla::ILexer5 *plex, const PropertyMap &propertyMap, std
|
|||
|
||||
// Set parameters of lexer
|
||||
for (auto const &[key, val] : propertyMap.properties) {
|
||||
if (key.starts_with("#")) {
|
||||
// Ignore comments
|
||||
} else if (key.starts_with("lexer.*")) {
|
||||
if (key.starts_with("lexer.*")) {
|
||||
// Ignore as processed earlier
|
||||
} else if (key.starts_with("keywords")) {
|
||||
// Ignore as processed earlier
|
||||
|
@ -455,16 +792,16 @@ bool TestFile(const std::filesystem::path &path, const PropertyMap &propertyMap)
|
|||
|
||||
plex->Release();
|
||||
|
||||
if (success) {
|
||||
Scintilla::ILexer5 *plexCRLF = Lexilla::MakeLexer(*language);
|
||||
SetProperties(plexCRLF, propertyMap, path.filename().string());
|
||||
TestCRLF(path, text, plexCRLF, disablePerLineTests);
|
||||
success = TestCRLF(path, text, plexCRLF, disablePerLineTests);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool TestDirectory(std::filesystem::path directory, std::filesystem::path basePath) {
|
||||
PropertyMap properties;
|
||||
properties.ReadFromFile(directory / "SciTE.properties");
|
||||
bool success = true;
|
||||
for (auto &p : std::filesystem::directory_iterator(directory)) {
|
||||
if (!p.is_directory()) {
|
||||
|
@ -473,6 +810,9 @@ bool TestDirectory(std::filesystem::path directory, std::filesystem::path basePa
|
|||
extension != suffixFolded) {
|
||||
const std::filesystem::path relativePath = p.path().lexically_relative(basePath);
|
||||
std::cout << "Lexing " << relativePath.string() << '\n';
|
||||
PropertyMap properties;
|
||||
properties.properties["FileNameExt"] = p.path().filename().string();
|
||||
properties.ReadFromFile(directory / "SciTE.properties");
|
||||
if (!TestFile(p, properties)) {
|
||||
success = false;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
code.page=65001
|
||||
lexer.*.md=markdown
|
||||
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
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
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
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
0 402 0 | i = 1
|
||||
0 402 0 | puts "Example"
|
||||
0 402 0 | end
|
||||
0 400 0 end
|
||||
0 401 0 | end
|
|
@ -1 +1 @@
|
|||
515
|
||||
516
|
|
@ -96,8 +96,7 @@ char ScintillaCall::CharacterAt(Position position) {
|
|||
}
|
||||
|
||||
int ScintillaCall::UnsignedStyleAt(Position position) {
|
||||
// Returns signed value but easier to use as unsigned
|
||||
return static_cast<unsigned char>(Call(Message::GetStyleAt, position));
|
||||
return static_cast<int>(Call(Message::GetStyleIndexAt, position));
|
||||
}
|
||||
|
||||
std::string ScintillaCall::StringOfSpan(Span span) {
|
||||
|
@ -192,6 +191,10 @@ int ScintillaCall::StyleAt(Position 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() {
|
||||
Call(Message::Redo);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.2.1</string>
|
||||
<string>5.2.2</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
|
|
@ -565,7 +565,7 @@
|
|||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 5.2.1;
|
||||
CURRENT_PROJECT_VERSION = 5.2.2;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
|
@ -627,7 +627,7 @@
|
|||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 5.2.1;
|
||||
CURRENT_PROJECT_VERSION = 5.2.2;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
|
@ -657,7 +657,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 5.2.1;
|
||||
CURRENT_PROJECT_VERSION = 5.2.2;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
@ -691,7 +691,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 5.2.1;
|
||||
CURRENT_PROJECT_VERSION = 5.2.2;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
|
|
@ -1100,7 +1100,7 @@ void ScintillaCocoa::CTPaint(void *gc, NSRect rc) {
|
|||
#pragma unused(rc)
|
||||
std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(Technology::Default));
|
||||
surfaceWindow->Init(gc, wMain.GetID());
|
||||
surfaceWindow->SetMode(SurfaceMode(ct.codePage, BidirectionalR2L()));
|
||||
surfaceWindow->SetMode(CurrentSurfaceMode());
|
||||
ct.PaintCT(surfaceWindow.get());
|
||||
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.
|
||||
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()));
|
||||
|
||||
const bool lastHideSelection = view.hideSelection;
|
||||
|
|
|
@ -129,7 +129,7 @@
|
|||
|
||||
<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
|
||||
<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_GETCHARAT">SCI_GETCHARAT(position pos) → int</a><br />
|
||||
<a class="message" href="#SCI_GETSTYLEAT">SCI_GETSTYLEAT(position pos) → int</a><br />
|
||||
<a class="message" href="#SCI_GETSTYLEINDEXAT">SCI_GETSTYLEINDEXAT(position pos) → int</a><br />
|
||||
<a class="message" href="#SCI_GETSTYLEDTEXT">SCI_GETSTYLEDTEXT(<unused>, Sci_TextRange *tr) → position</a><br />
|
||||
<a class="message" href="#SCI_RELEASEALLEXTENDEDSTYLES">SCI_RELEASEALLEXTENDEDSTYLES</a><br />
|
||||
<a class="message" href="#SCI_ALLOCATEEXTENDEDSTYLES">SCI_ALLOCATEEXTENDEDSTYLES(int numberStyles) → 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
|
||||
negative or past the end of the document.</p>
|
||||
|
||||
<p><b id="SCI_GETSTYLEAT">SCI_GETSTYLEAT(position pos) → int</b><br />
|
||||
<p>
|
||||
<b id="SCI_GETSTYLEAT">SCI_GETSTYLEAT(position pos) → int</b><br />
|
||||
<b id="SCI_GETSTYLEINDEXAT">SCI_GETSTYLEINDEXAT(position pos) → 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
|
||||
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 />
|
||||
<b id="SCI_ALLOCATEEXTENDEDSTYLES">SCI_ALLOCATEEXTENDEDSTYLES(int numberStyles) → int</b><br />
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<font size="4"> <a href="https://www.scintilla.org/scintilla521.zip">
|
||||
<font size="4"> <a href="https://www.scintilla.org/scintilla522.zip">
|
||||
Windows</a>
|
||||
<a href="https://www.scintilla.org/scintilla521.tgz">
|
||||
<a href="https://www.scintilla.org/scintilla522.tgz">
|
||||
GTK/Linux</a>
|
||||
</font>
|
||||
</td>
|
||||
|
@ -42,7 +42,7 @@
|
|||
containing very few restrictions.
|
||||
</p>
|
||||
<h3>
|
||||
Release 5.2.1
|
||||
Release 5.2.2
|
||||
</h3>
|
||||
<h4>
|
||||
Source Code
|
||||
|
@ -50,8 +50,8 @@
|
|||
The source code package contains all of the source code for Scintilla but no binary
|
||||
executable code and is available in
|
||||
<ul>
|
||||
<li><a href="https://www.scintilla.org/scintilla521.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.zip">zip format</a> (1.3M) commonly used on Windows</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>
|
||||
Instructions for building on both Windows and Linux are included in the readme file.
|
||||
<h4>
|
||||
|
|
|
@ -569,9 +569,37 @@
|
|||
</tr><tr>
|
||||
<td>Arkadiusz Michalski</td>
|
||||
<td>Christian Schmitz</td>
|
||||
<td>Michael Berlenz</td>
|
||||
</tr>
|
||||
</table>
|
||||
<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>
|
||||
<a href="https://www.scintilla.org/scintilla521.zip">Release 5.2.1</a>
|
||||
</h3>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" />
|
||||
<meta name="Description"
|
||||
content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." />
|
||||
<meta name="Date.Modified" content="20220224" />
|
||||
<meta name="Date.Modified" content="20220331" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style type="text/css">
|
||||
#versionlist {
|
||||
|
@ -56,8 +56,8 @@
|
|||
GTK, and macOS</font>
|
||||
</td>
|
||||
<td width="40%" align="right">
|
||||
<font color="#FFCC99" size="3"> Release version 5.2.1<br />
|
||||
Site last modified February 24 2022</font>
|
||||
<font color="#FFCC99" size="3"> Release version 5.2.2<br />
|
||||
Site last modified March 31 2022</font>
|
||||
</td>
|
||||
<td width="20%">
|
||||
|
||||
|
@ -72,6 +72,7 @@
|
|||
</tr>
|
||||
</table>
|
||||
<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.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>
|
||||
|
|
|
@ -822,6 +822,8 @@ void SurfaceImpl::DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITI
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class ClusterIterator {
|
||||
UniquePangoLayoutIter iter;
|
||||
PangoRectangle pos {};
|
||||
|
@ -836,6 +838,7 @@ public:
|
|||
lenPositions(static_cast<int>(text.length())) {
|
||||
LayoutSetText(layout, text);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -848,12 +851,24 @@ public:
|
|||
} else {
|
||||
finished = true;
|
||||
position = pango_units_to_double(pos.x + pos.width);
|
||||
curIndex = lenPositions;
|
||||
curIndex = pango_layout_iter_get_index(iter.get());
|
||||
}
|
||||
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) {
|
||||
if (PFont(font_)->fd) {
|
||||
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());
|
||||
if (et == EncodingType::utf8) {
|
||||
// Simple and direct as UTF-8 is native Pango encoding
|
||||
int i = 0;
|
||||
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) {
|
||||
iti.Next();
|
||||
const int places = iti.curIndex - i;
|
||||
|
@ -889,8 +909,13 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI
|
|||
// character byte lengths.
|
||||
Converter convMeasure("UCS-2", CharacterSetID(characterSet), false);
|
||||
int i = 0;
|
||||
int clusterStart = 0;
|
||||
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) {
|
||||
iti.Next();
|
||||
const int clusterEnd = iti.curIndex;
|
||||
|
@ -920,22 +945,22 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI
|
|||
utfForm = UTF8FromLatin1(text);
|
||||
}
|
||||
size_t i = 0;
|
||||
int clusterStart = 0;
|
||||
// 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.
|
||||
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) {
|
||||
iti.Next();
|
||||
const int clusterEnd = iti.curIndex;
|
||||
const int ligatureLength = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart);
|
||||
if (rtlCheck && ((clusterEnd <= clusterStart) || (ligatureLength == 0) || (ligatureLength > 3))) {
|
||||
// Something has gone wrong: exit quickly but pretend all the characters are equally spaced:
|
||||
int widthLayout = 0;
|
||||
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);
|
||||
}
|
||||
EquallySpaced(layoutMeasure.get(), positions, lenPositions);
|
||||
return;
|
||||
}
|
||||
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());
|
||||
// Simple and direct as UTF-8 is native Pango encoding
|
||||
int i = 0;
|
||||
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) {
|
||||
iti.Next();
|
||||
const int places = iti.curIndex - i;
|
||||
|
|
|
@ -1999,11 +1999,6 @@ gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) {
|
|||
// issues spurious button 2 mouse events during wheeling, which can cause
|
||||
// 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)
|
||||
// Smooth scrolling not supported
|
||||
if (event->direction == GDK_SCROLL_SMOOTH) {
|
||||
|
@ -2012,8 +2007,10 @@ gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) {
|
|||
#endif
|
||||
|
||||
// Horizontal scrolling
|
||||
if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT) {
|
||||
sciThis->HorizontalScrollTo(sciThis->xOffset + cLineScroll);
|
||||
if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT || event->state & GDK_SHIFT_MASK) {
|
||||
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
|
||||
} else if (event->state & GDK_CONTROL_MASK) {
|
||||
|
|
|
@ -15,10 +15,8 @@
|
|||
typedef ptrdiff_t Sci_Position;
|
||||
|
||||
// Unsigned variant used for ILexer::Lex and ILexer::Fold
|
||||
// Definitions of common types
|
||||
typedef size_t Sci_PositionU;
|
||||
|
||||
|
||||
// For Sci_CharacterRange which is defined as long to be compatible with Win32 CHARRANGE
|
||||
typedef intptr_t Sci_PositionCR;
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP
|
|||
#define SCI_GETCURRENTPOS 2008
|
||||
#define SCI_GETANCHOR 2009
|
||||
#define SCI_GETSTYLEAT 2010
|
||||
#define SCI_GETSTYLEINDEXAT 2038
|
||||
#define SCI_REDO 2011
|
||||
#define SCI_SETUNDOCOLLECTION 2012
|
||||
#define SCI_SELECTALL 2013
|
||||
|
|
|
@ -130,6 +130,9 @@ get position GetAnchor=2009(,)
|
|||
# Returns the style byte at the position.
|
||||
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.
|
||||
fun void Redo=2011(,)
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ public:
|
|||
Position CurrentPos();
|
||||
Position Anchor();
|
||||
int StyleAt(Position pos);
|
||||
int StyleIndexAt(Position pos);
|
||||
void Redo();
|
||||
void SetUndoCollection(bool collectUndo);
|
||||
void SelectAll();
|
||||
|
|
|
@ -28,6 +28,7 @@ enum class Message {
|
|||
GetCurrentPos = 2008,
|
||||
GetAnchor = 2009,
|
||||
GetStyleAt = 2010,
|
||||
GetStyleIndexAt = 2038,
|
||||
Redo = 2011,
|
||||
SetUndoCollection = 2012,
|
||||
SelectAll = 2013,
|
||||
|
|
|
@ -13,7 +13,7 @@ TEMPLATE = lib
|
|||
CONFIG += lib_bundle
|
||||
CONFIG += c++1z
|
||||
|
||||
VERSION = 5.2.1
|
||||
VERSION = 5.2.2
|
||||
|
||||
SOURCES += \
|
||||
ScintillaEdit.cpp \
|
||||
|
|
|
@ -339,19 +339,8 @@ void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern)
|
|||
{
|
||||
// Tile pattern over rectangle
|
||||
SurfaceImpl *surface = dynamic_cast<SurfaceImpl *>(&surfacePattern);
|
||||
// Currently assumes 8x8 pattern
|
||||
int widthPat = 8;
|
||||
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);
|
||||
}
|
||||
}
|
||||
const QPixmap *pixmap = static_cast<QPixmap *>(surface->GetPaintDevice());
|
||||
GetPainter()->drawTiledPixmap(QRectFromPRect(rc), *pixmap);
|
||||
}
|
||||
|
||||
void SurfaceImpl::RoundedRectangle(PRectangle rc, FillStroke fillStroke)
|
||||
|
|
|
@ -12,7 +12,7 @@ TEMPLATE = lib
|
|||
CONFIG += lib_bundle
|
||||
CONFIG += c++1z
|
||||
|
||||
VERSION = 5.2.1
|
||||
VERSION = 5.2.2
|
||||
|
||||
SOURCES += \
|
||||
PlatQt.cpp \
|
||||
|
|
|
@ -272,24 +272,14 @@ void CallTip::MouseClick(Point pt) noexcept {
|
|||
}
|
||||
|
||||
PRectangle CallTip::CallTipStart(Sci::Position pos, Point pt, int textHeight, const char *defn,
|
||||
const char *faceName, int size,
|
||||
int codePage_, CharacterSet characterSet,
|
||||
Technology technology,
|
||||
const char *localeName,
|
||||
const Window &wParent) {
|
||||
int codePage_, Surface *surfaceMeasure, std::shared_ptr<Font> font_) {
|
||||
clickPlace = 0;
|
||||
val = defn;
|
||||
codePage = codePage_;
|
||||
std::unique_ptr<Surface> surfaceMeasure = Surface::Allocate(technology);
|
||||
surfaceMeasure->Init(wParent.GetID());
|
||||
surfaceMeasure->SetMode(SurfaceMode(codePage, false));
|
||||
highlight = Chunk();
|
||||
inCallTipMode = true;
|
||||
posStartCallTip = pos;
|
||||
const XYPOSITION deviceHeight = static_cast<XYPOSITION>(surfaceMeasure->DeviceHeightFont(size));
|
||||
const FontParameters fp(faceName, deviceHeight / FontSizeMultiplier, FontWeight::Normal,
|
||||
false, FontQuality::QualityDefault, technology, characterSet, localeName);
|
||||
font = Font::Allocate(fp);
|
||||
font = font_;
|
||||
// Look for multiple lines in the text
|
||||
// Only support \n here - simply means container must avoid \r!
|
||||
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
|
||||
widthArrow = lineHeight * 9 / 10;
|
||||
#endif
|
||||
const int width = PaintContents(surfaceMeasure.get(), false) + insetX;
|
||||
const int width = PaintContents(surfaceMeasure, false) + insetX;
|
||||
|
||||
// The returned
|
||||
// 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
|
||||
// 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;
|
||||
colourUnSel = fore;
|
||||
}
|
||||
|
|
|
@ -71,9 +71,7 @@ public:
|
|||
|
||||
/// Setup the calltip and return a rectangle of the area required.
|
||||
PRectangle CallTipStart(Sci::Position pos, Point pt, int textHeight, const char *defn,
|
||||
const char *faceName, int size, int codePage_,
|
||||
Scintilla::CharacterSet characterSet, Scintilla::Technology technology, const char *localeName,
|
||||
const Window &wParent);
|
||||
int codePage_, Surface *surfaceMeasure, std::shared_ptr<Font> font_);
|
||||
|
||||
void CallTipCancel() noexcept;
|
||||
|
||||
|
@ -91,7 +89,7 @@ public:
|
|||
bool UseStyleCallTip() const noexcept;
|
||||
|
||||
// Modify foreground and background colours
|
||||
void SetForeBack(const ColourRGBA &fore, const ColourRGBA &back) noexcept;
|
||||
void SetForeBack(ColourRGBA fore, ColourRGBA back) noexcept;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -101,6 +101,10 @@ bool EditModel::BidirectionalR2L() const noexcept {
|
|||
return bidirectional == Bidirectional::R2L;
|
||||
}
|
||||
|
||||
SurfaceMode EditModel::CurrentSurfaceMode() const noexcept {
|
||||
return SurfaceMode(pdoc->dbcsCodePage, BidirectionalR2L());
|
||||
}
|
||||
|
||||
void EditModel::SetDefaultFoldDisplayText(const char *text) {
|
||||
defaultFoldDisplayText = IsNullOrEmpty(text) ? UniqueString() : UniqueStringCopy(text);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
virtual Sci::Line LinesOnScreen() const = 0;
|
||||
bool BidirectionalEnabled() const noexcept;
|
||||
bool BidirectionalR2L() const noexcept;
|
||||
SurfaceMode CurrentSurfaceMode() const noexcept;
|
||||
void SetDefaultFoldDisplayText(const char *text);
|
||||
const char *GetDefaultFoldDisplayText() const noexcept;
|
||||
const char *GetFoldDisplayText(Sci::Line lineDoc) const noexcept;
|
||||
|
|
|
@ -774,8 +774,8 @@ Point EditView::LocationFromPosition(Surface *surface, const EditModel &model, S
|
|||
}
|
||||
}
|
||||
pt.y += (lineVisible - topLine) * vs.lineHeight;
|
||||
}
|
||||
pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth;
|
||||
}
|
||||
return pt;
|
||||
}
|
||||
|
||||
|
@ -1485,7 +1485,9 @@ void EditView::DrawEOLAnnotationText(Surface *surface, const EditModel &model, c
|
|||
const char *textFoldDisplay = model.GetFoldDisplayText(line);
|
||||
if (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);
|
||||
|
||||
|
@ -2441,7 +2443,7 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectan
|
|||
surface = pixmapLine.get();
|
||||
PLATFORM_ASSERT(pixmapLine->Initialised());
|
||||
}
|
||||
surface->SetMode(SurfaceMode(model.pdoc->dbcsCodePage, model.BidirectionalR2L()));
|
||||
surface->SetMode(model.CurrentSurfaceMode());
|
||||
|
||||
const Point ptOrigin = model.GetVisibleOriginInMain();
|
||||
|
||||
|
|
|
@ -204,7 +204,6 @@ Editor::Editor() : durationWrapOneByte(0.000001, 0.00000001, 0.00001) {
|
|||
|
||||
Editor::~Editor() {
|
||||
pdoc->RemoveWatcher(this, nullptr);
|
||||
DropGraphics();
|
||||
}
|
||||
|
||||
void Editor::Finalise() {
|
||||
|
@ -1707,6 +1706,7 @@ void Editor::PaintSelMargin(Surface *surfaceWindow, const PRectangle &rc) {
|
|||
} else {
|
||||
surface = surfaceWindow;
|
||||
}
|
||||
surface->SetMode(CurrentSurfaceMode());
|
||||
|
||||
// Clip vertically to paint area to avoid drawing line numbers
|
||||
if (rcMargin.bottom > rc.bottom)
|
||||
|
@ -5687,6 +5687,26 @@ int Editor::CodePage() const noexcept {
|
|||
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) {
|
||||
AutoSurface surface(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
|
||||
return pdoc->StyleAt(PositionFromUPtr(wParam));
|
||||
|
||||
case Message::GetStyleIndexAt:
|
||||
if (PositionFromUPtr(wParam) >= pdoc->Length())
|
||||
return 0;
|
||||
else
|
||||
return pdoc->StyleIndexAt(PositionFromUPtr(wParam));
|
||||
|
||||
case Message::Redo:
|
||||
Redo();
|
||||
break;
|
||||
|
|
|
@ -592,6 +592,8 @@ protected: // ScintillaBase subclass needs access to much of Editor
|
|||
virtual bool ValidCodePage(int /* codePage */) const { return true; }
|
||||
virtual std::string UTF8FromEncoded(std::string_view encoded) 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);
|
||||
void AddStyledText(const char *buffer, Sci::Position appendLength);
|
||||
|
@ -684,19 +686,11 @@ class AutoSurface {
|
|||
private:
|
||||
std::unique_ptr<Surface> surf;
|
||||
public:
|
||||
AutoSurface(const Editor *ed) {
|
||||
if (ed->wMain.GetID()) {
|
||||
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(const Editor *ed) :
|
||||
surf(ed->CreateMeasurementSurface()) {
|
||||
}
|
||||
AutoSurface(SurfaceID sid, Editor *ed, std::optional<Scintilla::Technology> technology = {}) :
|
||||
surf(ed->CreateDrawingSurface(sid, technology)) {
|
||||
}
|
||||
// Deleted so AutoSurface objects can not be copied.
|
||||
AutoSurface(const AutoSurface &) = delete;
|
||||
|
|
|
@ -465,22 +465,20 @@ void ScintillaBase::CallTipShow(Point pt, const char *defn) {
|
|||
// StyleDefault for the face name, size and character set. Also use it
|
||||
// for the foreground and background colour.
|
||||
const int ctStyle = ct.UseStyleCallTip() ? StyleCallTip : StyleDefault;
|
||||
const Style &style = vs.styles[ctStyle];
|
||||
if (ct.UseStyleCallTip()) {
|
||||
ct.SetForeBack(vs.styles[StyleCallTip].fore, vs.styles[StyleCallTip].back);
|
||||
ct.SetForeBack(style.fore, style.back);
|
||||
}
|
||||
if (wMargin.Created()) {
|
||||
pt = pt + GetVisibleOriginInMain();
|
||||
}
|
||||
AutoSurface surfaceMeasure(this);
|
||||
PRectangle rc = ct.CallTipStart(sel.MainCaret(), pt,
|
||||
vs.lineHeight,
|
||||
defn,
|
||||
vs.styles[ctStyle].fontName,
|
||||
vs.styles[ctStyle].sizeZoomed,
|
||||
CodePage(),
|
||||
vs.styles[ctStyle].characterSet,
|
||||
vs.technology,
|
||||
vs.localeName.c_str(),
|
||||
wMain);
|
||||
surfaceMeasure,
|
||||
style.font);
|
||||
// If the call-tip window would be out of the client
|
||||
// space
|
||||
const PRectangle rcClient = GetClientRectangle();
|
||||
|
|
|
@ -133,7 +133,6 @@ ViewStyle::ViewStyle(size_t stylesSize_) :
|
|||
Element::SelectionSecondaryText,
|
||||
Element::SelectionSecondaryBack,
|
||||
Element::SelectionInactiveText,
|
||||
Element::SelectionBack,
|
||||
Element::SelectionInactiveBack,
|
||||
});
|
||||
|
||||
|
|
|
@ -48,13 +48,16 @@ class TestSimple(unittest.TestCase):
|
|||
|
||||
def testAddStyledText(self):
|
||||
self.assertEquals(self.ed.EndStyled, 0)
|
||||
self.ed.AddStyledText(2, b"x\002")
|
||||
self.assertEquals(self.ed.Length, 1)
|
||||
self.ed.AddStyledText(4, b"x\002y\377")
|
||||
self.assertEquals(self.ed.Length, 2)
|
||||
self.assertEquals(self.ed.GetCharAt(0), ord("x"))
|
||||
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(1, 2), b"y\377")
|
||||
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.GetStyleAt(0), 0)
|
||||
self.assertEquals(self.ed.StyledTextRange(0, 1), b"x\0")
|
||||
|
|
|
@ -1 +1 @@
|
|||
521
|
||||
522
|
||||
|
|
|
@ -19,14 +19,6 @@
|
|||
|
||||
namespace Scintilla::Internal::HanjaDict {
|
||||
|
||||
struct BSTRDeleter {
|
||||
void operator()(BSTR bstr) const noexcept {
|
||||
SysFreeString(bstr);
|
||||
}
|
||||
};
|
||||
|
||||
using UniqueBSTR = std::unique_ptr<OLECHAR[], BSTRDeleter>;
|
||||
|
||||
interface IRadical;
|
||||
interface IHanja;
|
||||
interface IStrokes;
|
||||
|
@ -66,6 +58,37 @@ interface IHanjaDic : IUnknown {
|
|||
extern "C" const GUID __declspec(selectany) IID_IHanjaDic =
|
||||
{ 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 {
|
||||
std::unique_ptr<IHanjaDic, UnknownReleaser> HJinterface;
|
||||
|
||||
|
@ -77,7 +100,7 @@ class HanjaDic {
|
|||
hr = CoCreateInstance(CLSID_HanjaDic, nullptr,
|
||||
CLSCTX_INPROC_SERVER, IID_IHanjaDic,
|
||||
(LPVOID *)&instance);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (SUCCEEDED(hr) && instance) {
|
||||
HJinterface.reset(instance);
|
||||
hr = instance->OpenMainDic();
|
||||
return SUCCEEDED(hr);
|
||||
|
@ -102,9 +125,9 @@ public:
|
|||
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;
|
||||
const HRESULT hr = HJinterface->HanjaToHangul(bstrHanja, &result);
|
||||
const HRESULT hr = HJinterface->HanjaToHangul(bstrHanja.get(), &result);
|
||||
bstrHangul.reset(result);
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
@ -121,11 +144,10 @@ bool GetHangulOfHanja(std::wstring &inout) noexcept {
|
|||
if (dict.Open()) {
|
||||
for (wchar_t &character : inout) {
|
||||
if (dict.IsHanja(character)) { // Pass hanja only!
|
||||
const UniqueBSTR bstrHanja{SysAllocStringLen(&character, 1)};
|
||||
UniqueBSTR bstrHangul;
|
||||
if (dict.HanjaToHangul(bstrHanja.get(), bstrHangul)) {
|
||||
ScopedBSTR bstrHangul;
|
||||
if (dict.HanjaToHangul(ScopedBSTR(character), bstrHangul)) {
|
||||
changed = true;
|
||||
character = bstrHangul[0];
|
||||
character = *(bstrHangul.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
#define NOMINMAX
|
||||
#endif
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#define _WIN32_WINNT 0x0A00
|
||||
#undef WINVER
|
||||
#define WINVER 0x0500
|
||||
#define WINVER 0x0A00
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
|
@ -58,14 +58,6 @@
|
|||
#include "WinTypes.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
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic ignored "-Wlanguage-extension-token"
|
||||
|
@ -80,8 +72,6 @@ UINT CodePageFromCharSet(CharacterSet characterSet, UINT documentCodePage) noexc
|
|||
#if defined(USE_D2D)
|
||||
IDWriteFactory *pIDWriteFactory = nullptr;
|
||||
ID2D1Factory *pD2DFactory = nullptr;
|
||||
IDWriteRenderingParams *defaultRenderingParams = nullptr;
|
||||
IDWriteRenderingParams *customClearTypeRenderingParams = nullptr;
|
||||
D2D1_DRAW_TEXT_OPTIONS d2dDrawTextOptions = D2D1_DRAW_TEXT_OPTIONS_NONE;
|
||||
|
||||
static HMODULE hDLLD2D {};
|
||||
|
@ -131,24 +121,6 @@ void LoadD2DOnce() noexcept {
|
|||
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() {
|
||||
|
@ -159,10 +131,6 @@ bool LoadD2D() {
|
|||
|
||||
#endif
|
||||
|
||||
#ifndef CLEARTYPE_QUALITY
|
||||
#define CLEARTYPE_QUALITY 5
|
||||
#endif
|
||||
|
||||
void *PointerFromWindow(HWND hWnd) noexcept {
|
||||
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 SurfaceD2D : public Surface {
|
||||
class SurfaceD2D : public Surface, public ISetRenderingParams {
|
||||
SurfaceMode mode;
|
||||
|
||||
ID2D1RenderTarget *pRenderTarget = nullptr;
|
||||
|
@ -1317,8 +1285,10 @@ class SurfaceD2D : public Surface {
|
|||
|
||||
ID2D1SolidColorBrush *pBrush = nullptr;
|
||||
|
||||
FontQuality fontQuality = FontQuality::QualityMask;
|
||||
static constexpr FontQuality invalidFontQuality = FontQuality::QualityMask;
|
||||
FontQuality fontQuality = invalidFontQuality;
|
||||
int logPixelsY = USER_DEFAULT_SCREEN_DPI;
|
||||
std::shared_ptr<RenderingParams> renderingParams;
|
||||
|
||||
void Clear() noexcept;
|
||||
void SetFontQuality(FontQuality extraFontFlag);
|
||||
|
@ -1392,6 +1362,8 @@ public:
|
|||
void PopClip() override;
|
||||
void FlushCachedState() override;
|
||||
void FlushDrawing() override;
|
||||
|
||||
void SetRenderingParams(std::shared_ptr<RenderingParams> renderingParams_) override;
|
||||
};
|
||||
|
||||
SurfaceD2D::SurfaceD2D() noexcept {
|
||||
|
@ -1443,7 +1415,7 @@ void SurfaceD2D::Release() noexcept {
|
|||
}
|
||||
|
||||
void SurfaceD2D::SetScale(WindowID wid) noexcept {
|
||||
fontQuality = FontQuality::QualityMask;
|
||||
fontQuality = invalidFontQuality;
|
||||
logPixelsY = DpiForWindow(wid);
|
||||
}
|
||||
|
||||
|
@ -1471,7 +1443,9 @@ void SurfaceD2D::Init(SurfaceID sid, WindowID wid) {
|
|||
}
|
||||
|
||||
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_) {
|
||||
|
@ -1498,15 +1472,14 @@ void SurfaceD2D::D2DPenColourAlpha(ColourRGBA fore) noexcept {
|
|||
}
|
||||
|
||||
void SurfaceD2D::SetFontQuality(FontQuality extraFontFlag) {
|
||||
if (fontQuality != extraFontFlag) {
|
||||
if ((fontQuality != extraFontFlag) && renderingParams) {
|
||||
fontQuality = extraFontFlag;
|
||||
const D2D1_TEXT_ANTIALIAS_MODE aaMode = DWriteMapFontQuality(extraFontFlag);
|
||||
|
||||
if (aaMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE && customClearTypeRenderingParams)
|
||||
pRenderTarget->SetTextRenderingParams(customClearTypeRenderingParams);
|
||||
else if (defaultRenderingParams)
|
||||
pRenderTarget->SetTextRenderingParams(defaultRenderingParams);
|
||||
|
||||
if (aaMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE && renderingParams->customRenderingParams) {
|
||||
pRenderTarget->SetTextRenderingParams(renderingParams->customRenderingParams.get());
|
||||
} else if (renderingParams->defaultRenderingParams) {
|
||||
pRenderTarget->SetTextRenderingParams(renderingParams->defaultRenderingParams.get());
|
||||
}
|
||||
pRenderTarget->SetTextAntialiasMode(aaMode);
|
||||
}
|
||||
}
|
||||
|
@ -2642,6 +2615,10 @@ void SurfaceD2D::FlushDrawing() {
|
|||
}
|
||||
}
|
||||
|
||||
void SurfaceD2D::SetRenderingParams(std::shared_ptr<RenderingParams> renderingParams_) {
|
||||
renderingParams = renderingParams_;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::unique_ptr<Surface> Surface::Allocate(Technology technology) {
|
||||
|
@ -3876,8 +3853,6 @@ void Platform_Initialise(void *hInstance) noexcept {
|
|||
void Platform_Finalise(bool fromDllMain) noexcept {
|
||||
#if defined(USE_D2D)
|
||||
if (!fromDllMain) {
|
||||
ReleaseUnknown(defaultRenderingParams);
|
||||
ReleaseUnknown(customClearTypeRenderingParams);
|
||||
ReleaseUnknown(pIDWriteFactory);
|
||||
ReleaseUnknown(pD2DFactory);
|
||||
if (hDLLDWrite) {
|
||||
|
|
|
@ -53,6 +53,15 @@ HCURSOR LoadReverseArrowCursor(UINT dpi) noexcept;
|
|||
extern bool LoadD2D();
|
||||
extern ID2D1Factory *pD2DFactory;
|
||||
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
|
||||
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#include <windows.h>
|
||||
|
||||
#define VERSION_SCINTILLA "5.2.1"
|
||||
#define VERSION_WORDS 5, 2, 1, 0
|
||||
#define VERSION_SCINTILLA "5.2.2"
|
||||
#define VERSION_WORDS 5, 2, 2, 0
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION_WORDS
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
#define NOMINMAX
|
||||
#endif
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#define _WIN32_WINNT 0x0A00
|
||||
#undef WINVER
|
||||
#define WINVER 0x0500
|
||||
#define WINVER 0x0A00
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
|
@ -147,12 +147,6 @@ constexpr int IndicatorTarget = IndicatorInput + 1;
|
|||
constexpr int IndicatorConverted = IndicatorInput + 2;
|
||||
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,
|
||||
UINT uElapse, TIMERPROC lpTimerFunc, ULONG uToleranceDelay);
|
||||
|
||||
|
@ -356,6 +350,9 @@ class ScintillaWin :
|
|||
#if defined(USE_D2D)
|
||||
ID2D1RenderTarget *pRenderTarget;
|
||||
bool renderTargetValid;
|
||||
// rendering parameters for current monitor
|
||||
HMONITOR hCurrentMonitor;
|
||||
std::shared_ptr<RenderingParams> renderingParams;
|
||||
#endif
|
||||
|
||||
explicit ScintillaWin(HWND hwnd);
|
||||
|
@ -368,6 +365,7 @@ class ScintillaWin :
|
|||
|
||||
void Finalise() override;
|
||||
#if defined(USE_D2D)
|
||||
bool UpdateRenderingParams(bool force) noexcept;
|
||||
void EnsureRenderTarget(HDC hdc);
|
||||
#endif
|
||||
void DropRenderTarget() noexcept;
|
||||
|
@ -392,6 +390,8 @@ class ScintillaWin :
|
|||
Sci::Position TargetAsUTF8(char *text) const;
|
||||
Sci::Position EncodedFromUTF8(const char *utf8, char *encoded) const;
|
||||
|
||||
void SetRenderingParams(Surface *psurf) const;
|
||||
|
||||
bool PaintDC(HDC hdc);
|
||||
sptr_t WndPaint();
|
||||
|
||||
|
@ -571,6 +571,7 @@ ScintillaWin::ScintillaWin(HWND hwnd) {
|
|||
#if defined(USE_D2D)
|
||||
pRenderTarget = nullptr;
|
||||
renderTargetValid = true;
|
||||
hCurrentMonitor = {};
|
||||
#endif
|
||||
|
||||
caret.period = ::GetCaretBlinkTime();
|
||||
|
@ -615,6 +616,38 @@ void ScintillaWin::Finalise() {
|
|||
|
||||
#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) {
|
||||
if (!renderTargetValid) {
|
||||
DropRenderTarget();
|
||||
|
@ -684,7 +717,6 @@ void ScintillaWin::EnsureRenderTarget(HDC hdc) {
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
void ScintillaWin::DropRenderTarget() noexcept {
|
||||
#if defined(USE_D2D)
|
||||
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) {
|
||||
if (technology == Technology::Default) {
|
||||
AutoSurface surfaceWindow(hdc, this);
|
||||
|
@ -924,6 +967,7 @@ bool ScintillaWin::PaintDC(HDC hdc) {
|
|||
if (pRenderTarget) {
|
||||
AutoSurface surfaceWindow(pRenderTarget, this);
|
||||
if (surfaceWindow) {
|
||||
SetRenderingParams(surfaceWindow);
|
||||
pRenderTarget->BeginDraw();
|
||||
Paint(surfaceWindow, rcPaint);
|
||||
surfaceWindow->Release();
|
||||
|
@ -1887,9 +1931,11 @@ sptr_t ScintillaWin::SciMessage(Message iMessage, uptr_t wParam, sptr_t lParam)
|
|||
if (technology != technologyNew) {
|
||||
if (technologyNew > Technology::Default) {
|
||||
#if defined(USE_D2D)
|
||||
if (!LoadD2D())
|
||||
if (!LoadD2D()) {
|
||||
// Failed to load Direct2D or DirectWrite so no effect
|
||||
return 0;
|
||||
}
|
||||
UpdateRenderingParams(true);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -1900,7 +1946,6 @@ sptr_t ScintillaWin::SciMessage(Message iMessage, uptr_t wParam, sptr_t lParam)
|
|||
technology = technologyNew;
|
||||
view.bufferedDraw = technologyNew == Technology::Default;
|
||||
// Invalidate all cached information including layout.
|
||||
DropGraphics();
|
||||
InvalidateStyleRedraw();
|
||||
}
|
||||
}
|
||||
|
@ -1913,7 +1958,6 @@ sptr_t ScintillaWin::SciMessage(Message iMessage, uptr_t wParam, sptr_t lParam)
|
|||
bidirectional = static_cast<Bidirectional>(wParam);
|
||||
}
|
||||
// Invalidate all cached information including layout.
|
||||
DropGraphics();
|
||||
InvalidateStyleRedraw();
|
||||
break;
|
||||
|
||||
|
@ -2017,10 +2061,15 @@ sptr_t ScintillaWin::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
|
|||
|
||||
case WM_SETTINGCHANGE:
|
||||
//Platform::DebugPrintf("Setting Changed\n");
|
||||
#if defined(USE_D2D)
|
||||
if (technology != Technology::Default) {
|
||||
UpdateRenderingParams(true);
|
||||
}
|
||||
#endif
|
||||
UpdateBaseElements();
|
||||
InvalidateStyleData();
|
||||
// Get Intellimouse scroll line parameters
|
||||
GetIntelliMouseParameters();
|
||||
InvalidateStyleRedraw();
|
||||
break;
|
||||
|
||||
case WM_GETDLGCODE:
|
||||
|
@ -2081,7 +2130,17 @@ sptr_t ScintillaWin::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
|
|||
case WM_NCLBUTTONDOWN:
|
||||
case WM_SYSCOMMAND:
|
||||
case WM_WINDOWPOSCHANGING:
|
||||
return ::DefWindowProc(MainHWND(), msg, wParam, lParam);
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
#if defined(USE_D2D)
|
||||
if (technology != Technology::Default) {
|
||||
if (UpdateRenderingParams(false)) {
|
||||
DropGraphics();
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ::DefWindowProc(MainHWND(), msg, wParam, lParam);
|
||||
|
||||
case WM_GETTEXTLENGTH:
|
||||
|
@ -3562,11 +3621,11 @@ LRESULT PASCAL ScintillaWin::CTWndProc(
|
|||
#endif
|
||||
RECT rc;
|
||||
GetClientRect(hWnd, &rc);
|
||||
// Create a Direct2D render target.
|
||||
if (sciThis->technology == Technology::Default) {
|
||||
surfaceWindow->Init(ps.hdc, hWnd);
|
||||
} else {
|
||||
#if defined(USE_D2D)
|
||||
// Create a Direct2D render target.
|
||||
D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp {};
|
||||
dhrtp.hwnd = hWnd;
|
||||
dhrtp.pixelSize = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
|
||||
|
@ -3595,7 +3654,8 @@ LRESULT PASCAL ScintillaWin::CTWndProc(
|
|||
}
|
||||
#endif
|
||||
}
|
||||
surfaceWindow->SetMode(SurfaceMode(sciThis->ct.codePage, sciThis->BidirectionalR2L()));
|
||||
surfaceWindow->SetMode(sciThis->CurrentSurfaceMode());
|
||||
sciThis->SetRenderingParams(surfaceWindow.get());
|
||||
sciThis->ct.PaintCT(surfaceWindow.get());
|
||||
#if defined(USE_D2D)
|
||||
if (pCTRenderTarget)
|
||||
|
|
|
@ -21,7 +21,7 @@ LD=link
|
|||
!IFDEF SUPPORT_XP
|
||||
ADD_DEFINE=-D_USING_V110_SDK71_
|
||||
# Different subsystems for 32-bit and 64-bit Windows XP so detect based on Platform
|
||||
# environment vairable set by vcvars*.bat to be either x86 or x64
|
||||
# environment variable set by vcvars*.bat to be either x86 or x64
|
||||
!IF "$(PLATFORM)" == "x64"
|
||||
SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.02
|
||||
!ELSE
|
||||
|
|
Loading…
Reference in New Issue