aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj8
-rw-r--r--doc/ScintillaHistory.html13
-rw-r--r--include/SciLexer.h30
-rw-r--r--include/Scintilla.iface34
-rw-r--r--lexers/LexSAS.cxx220
-rw-r--r--lexers/LexStata.cxx203
-rw-r--r--src/Catalogue.cxx2
-rw-r--r--win32/scintilla.mak6
8 files changed, 516 insertions, 0 deletions
diff --git a/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj b/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj
index 4658ed67b..e2df2d63d 100644
--- a/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj
+++ b/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj
@@ -227,6 +227,8 @@
8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; };
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; };
F437405F9F32C7DEFCA38C11 /* LexIndent.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 282E41F3B9E2BFEDD6A05BE7 /* LexIndent.cxx */; };
+ FDC7442CAD70B9A67EF1639D /* LexSAS.cxx in Sources */ = {isa = PBXBuildFile; fileRef = A95147A1AB7CADB00DAFE724 /* LexSAS.cxx */; };
+ 5F804AA6B60FE695863A39FE /* LexStata.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 7623427695416AB1270EE023 /* LexStata.cxx */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -457,6 +459,8 @@
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8DC2EF5B0486A6940098B216 /* Scintilla.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Scintilla.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D2F7E79907B2D74100F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
+ A95147A1AB7CADB00DAFE724 /* LexSAS.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexSAS.cxx; path = ../../lexers/LexSAS.cxx; sourceTree = SOURCE_ROOT; };
+ 7623427695416AB1270EE023 /* LexStata.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexStata.cxx; path = ../../lexers/LexStata.cxx; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -640,6 +644,7 @@
28A7D6041995E47D0062D204 /* LexRegistry.cxx */,
114B6EFB11FA7526004FB6AB /* LexRuby.cxx */,
1160E0371803651C00BCEBCB /* LexRust.cxx */,
+ A95147A1AB7CADB00DAFE724 /* LexSAS.cxx */,
114B6EFC11FA7526004FB6AB /* LexScriptol.cxx */,
114B6EFD11FA7526004FB6AB /* LexSmalltalk.cxx */,
114B6EFE11FA7526004FB6AB /* LexSML.cxx */,
@@ -647,6 +652,7 @@
114B6F0011FA7526004FB6AB /* LexSpecman.cxx */,
114B6F0111FA7526004FB6AB /* LexSpice.cxx */,
114B6F0211FA7526004FB6AB /* LexSQL.cxx */,
+ 7623427695416AB1270EE023 /* LexStata.cxx */,
11FDAEB6174E1A9700FA161B /* LexSTTXT.cxx */,
114B6F0311FA7526004FB6AB /* LexTACL.cxx */,
114B6F0411FA7526004FB6AB /* LexTADS3.cxx */,
@@ -1112,6 +1118,8 @@
11FF3FE21810EB3900E13F13 /* LexDMAP.cxx in Sources */,
F437405F9F32C7DEFCA38C11 /* LexIndent.cxx in Sources */,
3D994BD7A5EAC4FA5B3CFBDF /* LexMaxima.cxx in Sources */,
+ FDC7442CAD70B9A67EF1639D /* LexSAS.cxx in Sources */,
+ 5F804AA6B60FE695863A39FE /* LexStata.cxx in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index ec670d803..8d000f0d8 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -530,6 +530,7 @@
<td>Giuseppe Corbelli</td>
<td>Andreas Rönnquist</td>
<td>Henrik Hank</td>
+ <td>Luke Rasmussen</td>
</tr>
</table>
<p>
@@ -542,6 +543,18 @@
</li>
</ul>
<h3>
+ <a href="https://www.scintilla.org/scite411.zip">Release 4.1.1</a>
+ </h3>
+ <ul>
+ <li>
+ Released 19 June 2018.
+ </li>
+ <li>
+ Lexers added for SAS and Stata.
+ <a href="https://sourceforge.net/p/scintilla/feature-requests/1185/">Feature #1185.</a>
+ </li>
+ </ul>
+ <h3>
<a href="https://www.scintilla.org/scite410.zip">Release 4.1.0</a>
</h3>
<ul>
diff --git a/include/SciLexer.h b/include/SciLexer.h
index f4ef9954b..b6f864c6d 100644
--- a/include/SciLexer.h
+++ b/include/SciLexer.h
@@ -136,6 +136,8 @@
#define SCLEX_EDIFACT 121
#define SCLEX_INDENT 122
#define SCLEX_MAXIMA 123
+#define SCLEX_STATA 124
+#define SCLEX_SAS 125
#define SCLEX_AUTOMATIC 1000
#define SCE_P_DEFAULT 0
#define SCE_P_COMMENTLINE 1
@@ -1825,6 +1827,34 @@
#define SCE_EDI_UNA 6
#define SCE_EDI_UNH 7
#define SCE_EDI_BADSEGMENT 8
+#define SCE_STATA_DEFAULT 0
+#define SCE_STATA_COMMENT 1
+#define SCE_STATA_COMMENTLINE 2
+#define SCE_STATA_COMMENTBLOCK 3
+#define SCE_STATA_NUMBER 4
+#define SCE_STATA_OPERATOR 5
+#define SCE_STATA_IDENTIFIER 6
+#define SCE_STATA_STRING 7
+#define SCE_STATA_TYPE 8
+#define SCE_STATA_WORD 9
+#define SCE_STATA_GLOBAL_MACRO 10
+#define SCE_STATA_MACRO 11
+#define SCE_SAS_DEFAULT 0
+#define SCE_SAS_COMMENT 1
+#define SCE_SAS_COMMENTLINE 2
+#define SCE_SAS_COMMENTBLOCK 3
+#define SCE_SAS_NUMBER 4
+#define SCE_SAS_OPERATOR 5
+#define SCE_SAS_IDENTIFIER 6
+#define SCE_SAS_STRING 7
+#define SCE_SAS_TYPE 8
+#define SCE_SAS_WORD 9
+#define SCE_SAS_GLOBAL_MACRO 10
+#define SCE_SAS_MACRO 11
+#define SCE_SAS_MACRO_KEYWORD 12
+#define SCE_SAS_BLOCK_KEYWORD 13
+#define SCE_SAS_MACRO_FUNCTION 14
+#define SCE_SAS_STATEMENT 15
/* --Autogenerated -- end of section automatically generated from Scintilla.iface */
#endif
diff --git a/include/Scintilla.iface b/include/Scintilla.iface
index 8b08f4d2f..420a529a0 100644
--- a/include/Scintilla.iface
+++ b/include/Scintilla.iface
@@ -2932,6 +2932,8 @@ val SCLEX_JSON=120
val SCLEX_EDIFACT=121
val SCLEX_INDENT=122
val SCLEX_MAXIMA=123
+val SCLEX_STATA=124
+val SCLEX_SAS=125
# When a lexer specifies its language as SCLEX_AUTOMATIC it receives a
# value assigned in sequence from SCLEX_AUTOMATIC+1.
@@ -4853,6 +4855,38 @@ val SCE_EDI_SEP_RELEASE=5
val SCE_EDI_UNA=6
val SCE_EDI_UNH=7
val SCE_EDI_BADSEGMENT=8
+# Lexical states for SCLEX_STATA
+lex STATA=SCLEX_STATA SCE_STATA_
+val SCE_STATA_DEFAULT=0
+val SCE_STATA_COMMENT=1
+val SCE_STATA_COMMENTLINE=2
+val SCE_STATA_COMMENTBLOCK=3
+val SCE_STATA_NUMBER=4
+val SCE_STATA_OPERATOR=5
+val SCE_STATA_IDENTIFIER=6
+val SCE_STATA_STRING=7
+val SCE_STATA_TYPE=8
+val SCE_STATA_WORD=9
+val SCE_STATA_GLOBAL_MACRO=10
+val SCE_STATA_MACRO=11
+# Lexical states for SCLEX_SAS
+lex SAS=SCLEX_SAS SCE_SAS_
+val SCE_SAS_DEFAULT=0
+val SCE_SAS_COMMENT=1
+val SCE_SAS_COMMENTLINE=2
+val SCE_SAS_COMMENTBLOCK=3
+val SCE_SAS_NUMBER=4
+val SCE_SAS_OPERATOR=5
+val SCE_SAS_IDENTIFIER=6
+val SCE_SAS_STRING=7
+val SCE_SAS_TYPE=8
+val SCE_SAS_WORD=9
+val SCE_SAS_GLOBAL_MACRO=10
+val SCE_SAS_MACRO=11
+val SCE_SAS_MACRO_KEYWORD=12
+val SCE_SAS_BLOCK_KEYWORD=13
+val SCE_SAS_MACRO_FUNCTION=14
+val SCE_SAS_STATEMENT=15
# Events
diff --git a/lexers/LexSAS.cxx b/lexers/LexSAS.cxx
new file mode 100644
index 000000000..29feba82d
--- /dev/null
+++ b/lexers/LexSAS.cxx
@@ -0,0 +1,220 @@
+// Scintilla source code edit control
+/** @file LexSAS.cxx
+ ** Lexer for SAS
+ **/
+// Author: Luke Rasmussen (luke.rasmussen@gmail.com)
+//
+// The License.txt file describes the conditions under which this software may
+// be distributed.
+//
+// Developed as part of the StatTag project at Northwestern University Feinberg
+// School of Medicine with funding from Northwestern University Clinical and
+// Translational Sciences Institute through CTSA grant UL1TR001422. This work
+// has not been reviewed or endorsed by NCATS or the NIH.
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "ILexer.h"
+#include "Scintilla.h"
+#include "SciLexer.h"
+
+#include "WordList.h"
+#include "LexAccessor.h"
+#include "Accessor.h"
+#include "StyleContext.h"
+#include "CharacterSet.h"
+#include "LexerModule.h"
+
+using namespace Scintilla;
+
+static void ColouriseSASDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
+ Accessor &styler) {
+
+ WordList &keywords = *keywordlists[0];
+ WordList &blockKeywords = *keywordlists[1];
+ WordList &functionKeywords = *keywordlists[2];
+ WordList &statements = *keywordlists[3];
+
+ CharacterSet setCouldBePostOp(CharacterSet::setNone, "+-");
+ CharacterSet setMacroStart(CharacterSet::setNone, "%");
+ CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
+ CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true);
+
+ StyleContext sc(startPos, length, initStyle, styler);
+ bool lineHasNonCommentChar = false;
+ for (; sc.More(); sc.Forward()) {
+ if (sc.atLineStart) {
+ lineHasNonCommentChar = false;
+ }
+
+ // Determine if the current state should terminate.
+ switch (sc.state) {
+ case SCE_SAS_OPERATOR:
+ sc.SetState(SCE_SAS_DEFAULT);
+ break;
+ case SCE_SAS_NUMBER:
+ // We accept almost anything because of hex. and number suffixes
+ if (!setWord.Contains(sc.ch)) {
+ sc.SetState(SCE_SAS_DEFAULT);
+ }
+ break;
+ case SCE_SAS_MACRO:
+ if (!setWord.Contains(sc.ch) || (sc.ch == '.')) {
+ char s[1000];
+ sc.GetCurrentLowered(s, sizeof(s));
+ if (keywords.InList(s)) {
+ sc.ChangeState(SCE_SAS_MACRO_KEYWORD);
+ }
+ else if (blockKeywords.InList(s)) {
+ sc.ChangeState(SCE_SAS_BLOCK_KEYWORD);
+ }
+ else if (functionKeywords.InList(s)) {
+ sc.ChangeState(SCE_SAS_MACRO_FUNCTION);
+ }
+ sc.SetState(SCE_SAS_DEFAULT);
+ }
+ break;
+ case SCE_SAS_IDENTIFIER:
+ if (!setWord.Contains(sc.ch) || (sc.ch == '.')) {
+ char s[1000];
+ sc.GetCurrentLowered(s, sizeof(s));
+ if (statements.InList(s)) {
+ sc.ChangeState(SCE_SAS_STATEMENT);
+ }
+ else if(blockKeywords.InList(s)) {
+ sc.ChangeState(SCE_SAS_BLOCK_KEYWORD);
+ }
+ sc.SetState(SCE_SAS_DEFAULT);
+ }
+ break;
+ case SCE_SAS_COMMENTBLOCK:
+ if (sc.Match('*', '/')) {
+ sc.Forward();
+ sc.ForwardSetState(SCE_SAS_DEFAULT);
+ }
+ break;
+ case SCE_SAS_COMMENT:
+ case SCE_SAS_COMMENTLINE:
+ if (sc.Match(';')) {
+ sc.Forward();
+ sc.SetState(SCE_SAS_DEFAULT);
+ }
+ break;
+ case SCE_SAS_STRING:
+ if (sc.ch == '\"') {
+ sc.ForwardSetState(SCE_SAS_DEFAULT);
+ }
+ break;
+ }
+
+ // Determine if a new state should be entered.
+ if (sc.state == SCE_SAS_DEFAULT) {
+ if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
+ lineHasNonCommentChar = true;
+ sc.SetState(SCE_SAS_NUMBER);
+ }
+ else if (setWordStart.Contains(sc.ch)) {
+ lineHasNonCommentChar = true;
+ sc.SetState(SCE_SAS_IDENTIFIER);
+ }
+ else if (sc.Match('*') && !lineHasNonCommentChar) {
+ sc.SetState(SCE_SAS_COMMENT);
+ }
+ else if (sc.Match('/', '*')) {
+ sc.SetState(SCE_SAS_COMMENTBLOCK);
+ sc.Forward(); // Eat the * so it isn't used for the end of the comment
+ }
+ else if (sc.Match('/', '/')) {
+ sc.SetState(SCE_SAS_COMMENTLINE);
+ }
+ else if (sc.ch == '\"') {
+ lineHasNonCommentChar = true;
+ sc.SetState(SCE_SAS_STRING);
+ }
+ else if (setMacroStart.Contains(sc.ch)) {
+ lineHasNonCommentChar = true;
+ sc.SetState(SCE_SAS_MACRO);
+ }
+ else if (isoperator(static_cast<char>(sc.ch))) {
+ lineHasNonCommentChar = true;
+ sc.SetState(SCE_SAS_OPERATOR);
+ }
+ }
+ }
+
+ sc.Complete();
+}
+
+// Store both the current line's fold level and the next lines in the
+// level store to make it easy to pick up with each increment
+// and to make it possible to fiddle the current level for "} else {".
+static void FoldSASDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[],
+ Accessor &styler) {
+ bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
+ bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
+ Sci_PositionU endPos = startPos + length;
+ int visibleChars = 0;
+ Sci_Position lineCurrent = styler.GetLine(startPos);
+ int levelCurrent = SC_FOLDLEVELBASE;
+ if (lineCurrent > 0)
+ levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16;
+ int levelMinCurrent = levelCurrent;
+ int levelNext = levelCurrent;
+ char chNext = styler[startPos];
+ int styleNext = styler.StyleAt(startPos);
+ for (Sci_PositionU i = startPos; i < endPos; i++) {
+ char ch = chNext;
+ chNext = styler.SafeGetCharAt(i + 1);
+ int style = styleNext;
+ styleNext = styler.StyleAt(i + 1);
+ bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
+ if (style == SCE_R_OPERATOR) {
+ if (ch == '{') {
+ // Measure the minimum before a '{' to allow
+ // folding on "} else {"
+ if (levelMinCurrent > levelNext) {
+ levelMinCurrent = levelNext;
+ }
+ levelNext++;
+ }
+ else if (ch == '}') {
+ levelNext--;
+ }
+ }
+ if (atEOL) {
+ int levelUse = levelCurrent;
+ if (foldAtElse) {
+ levelUse = levelMinCurrent;
+ }
+ int lev = levelUse | levelNext << 16;
+ if (visibleChars == 0 && foldCompact)
+ lev |= SC_FOLDLEVELWHITEFLAG;
+ if (levelUse < levelNext)
+ lev |= SC_FOLDLEVELHEADERFLAG;
+ if (lev != styler.LevelAt(lineCurrent)) {
+ styler.SetLevel(lineCurrent, lev);
+ }
+ lineCurrent++;
+ levelCurrent = levelNext;
+ levelMinCurrent = levelCurrent;
+ visibleChars = 0;
+ }
+ if (!isspacechar(ch))
+ visibleChars++;
+ }
+}
+
+
+static const char * const SASWordLists[] = {
+ "Language Keywords",
+ "Macro Keywords",
+ "Types",
+ 0,
+};
+
+LexerModule lmSAS(SCLEX_SAS, ColouriseSASDoc, "sas", FoldSASDoc, SASWordLists);
diff --git a/lexers/LexStata.cxx b/lexers/LexStata.cxx
new file mode 100644
index 000000000..78410c627
--- /dev/null
+++ b/lexers/LexStata.cxx
@@ -0,0 +1,203 @@
+// Scintilla source code edit control
+/** @file LexStata.cxx
+ ** Lexer for Stata
+ **/
+// Author: Luke Rasmussen (luke.rasmussen@gmail.com)
+//
+// The License.txt file describes the conditions under which this software may
+// be distributed.
+//
+// Developed as part of the StatTag project at Northwestern University Feinberg
+// School of Medicine with funding from Northwestern University Clinical and
+// Translational Sciences Institute through CTSA grant UL1TR001422. This work
+// has not been reviewed or endorsed by NCATS or the NIH.
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "ILexer.h"
+#include "Scintilla.h"
+#include "SciLexer.h"
+
+#include "WordList.h"
+#include "LexAccessor.h"
+#include "Accessor.h"
+#include "StyleContext.h"
+#include "CharacterSet.h"
+#include "LexerModule.h"
+
+using namespace Scintilla;
+
+static void ColouriseStataDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
+ Accessor &styler) {
+
+ WordList &keywords = *keywordlists[0];
+ WordList &types = *keywordlists[1];
+
+ CharacterSet setCouldBePostOp(CharacterSet::setNone, "+-");
+ CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
+ CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true);
+
+ StyleContext sc(startPos, length, initStyle, styler);
+ bool lineHasNonCommentChar = false;
+ for (; sc.More(); sc.Forward()) {
+ if (sc.atLineStart) {
+ lineHasNonCommentChar = false;
+ }
+
+ // Determine if the current state should terminate.
+ switch (sc.state) {
+ case SCE_STATA_OPERATOR:
+ sc.SetState(SCE_STATA_DEFAULT);
+ break;
+ case SCE_STATA_NUMBER:
+ // We accept almost anything because of hex. and number suffixes
+ if (!setWord.Contains(sc.ch)) {
+ sc.SetState(SCE_STATA_DEFAULT);
+ }
+ break;
+ case SCE_STATA_IDENTIFIER:
+ if (!setWord.Contains(sc.ch) || (sc.ch == '.')) {
+ char s[1000];
+ sc.GetCurrent(s, sizeof(s));
+ if (keywords.InList(s)) {
+ sc.ChangeState(SCE_STATA_WORD);
+ }
+ else if (types.InList(s)) {
+ sc.ChangeState(SCE_STATA_TYPE);
+ }
+ sc.SetState(SCE_STATA_DEFAULT);
+ }
+ break;
+ case SCE_STATA_COMMENTBLOCK:
+ if (sc.Match('*', '/')) {
+ sc.Forward();
+ sc.ForwardSetState(SCE_STATA_DEFAULT);
+ }
+ break;
+ case SCE_STATA_COMMENT:
+ case SCE_STATA_COMMENTLINE:
+ if (sc.atLineStart) {
+ sc.SetState(SCE_STATA_DEFAULT);
+ }
+ break;
+ case SCE_STATA_STRING:
+ if (sc.ch == '\\') {
+ // Per Stata documentation, the following characters are the only ones that can
+ // be escaped (not our typical set of quotes, etc.):
+ // https://www.stata.com/support/faqs/programming/backslashes-and-macros/
+ if (sc.chNext == '$' || sc.chNext == '`' || sc.chNext == '\\') {
+ sc.Forward();
+ }
+ }
+ else if (sc.ch == '\"') {
+ sc.ForwardSetState(SCE_STATA_DEFAULT);
+ }
+ break;
+ }
+
+ // Determine if a new state should be entered.
+ if (sc.state == SCE_STATA_DEFAULT) {
+ if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
+ lineHasNonCommentChar = true;
+ sc.SetState(SCE_STATA_NUMBER);
+ }
+ else if (setWordStart.Contains(sc.ch)) {
+ lineHasNonCommentChar = true;
+ sc.SetState(SCE_STATA_IDENTIFIER);
+ }
+ else if (sc.Match('*') && !lineHasNonCommentChar) {
+ sc.SetState(SCE_STATA_COMMENT);
+ }
+ else if (sc.Match('/', '*')) {
+ sc.SetState(SCE_STATA_COMMENTBLOCK);
+ sc.Forward(); // Eat the * so it isn't used for the end of the comment
+ }
+ else if (sc.Match('/', '/')) {
+ sc.SetState(SCE_STATA_COMMENTLINE);
+ }
+ else if (sc.ch == '\"') {
+ lineHasNonCommentChar = true;
+ sc.SetState(SCE_STATA_STRING);
+ }
+ else if (isoperator(sc.ch)) {
+ lineHasNonCommentChar = true;
+ sc.SetState(SCE_STATA_OPERATOR);
+ }
+ }
+ }
+
+ sc.Complete();
+}
+
+// Store both the current line's fold level and the next lines in the
+// level store to make it easy to pick up with each increment
+// and to make it possible to fiddle the current level for "} else {".
+static void FoldStataDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[],
+ Accessor &styler) {
+ bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
+ bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
+ Sci_PositionU endPos = startPos + length;
+ int visibleChars = 0;
+ Sci_Position lineCurrent = styler.GetLine(startPos);
+ int levelCurrent = SC_FOLDLEVELBASE;
+ if (lineCurrent > 0)
+ levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16;
+ int levelMinCurrent = levelCurrent;
+ int levelNext = levelCurrent;
+ char chNext = styler[startPos];
+ int styleNext = styler.StyleAt(startPos);
+ for (Sci_PositionU i = startPos; i < endPos; i++) {
+ char ch = chNext;
+ chNext = styler.SafeGetCharAt(i + 1);
+ int style = styleNext;
+ styleNext = styler.StyleAt(i + 1);
+ bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
+ if (style == SCE_R_OPERATOR) {
+ if (ch == '{') {
+ // Measure the minimum before a '{' to allow
+ // folding on "} else {"
+ if (levelMinCurrent > levelNext) {
+ levelMinCurrent = levelNext;
+ }
+ levelNext++;
+ }
+ else if (ch == '}') {
+ levelNext--;
+ }
+ }
+ if (atEOL) {
+ int levelUse = levelCurrent;
+ if (foldAtElse) {
+ levelUse = levelMinCurrent;
+ }
+ int lev = levelUse | levelNext << 16;
+ if (visibleChars == 0 && foldCompact)
+ lev |= SC_FOLDLEVELWHITEFLAG;
+ if (levelUse < levelNext)
+ lev |= SC_FOLDLEVELHEADERFLAG;
+ if (lev != styler.LevelAt(lineCurrent)) {
+ styler.SetLevel(lineCurrent, lev);
+ }
+ lineCurrent++;
+ levelCurrent = levelNext;
+ levelMinCurrent = levelCurrent;
+ visibleChars = 0;
+ }
+ if (!isspacechar(ch))
+ visibleChars++;
+ }
+}
+
+
+static const char * const StataWordLists[] = {
+ "Language Keywords",
+ "Types",
+ 0,
+};
+
+LexerModule lmStata(SCLEX_STATA, ColouriseStataDoc, "stata", FoldStataDoc, StataWordLists);
diff --git a/src/Catalogue.cxx b/src/Catalogue.cxx
index 438fd2ba1..979aaa1d7 100644
--- a/src/Catalogue.cxx
+++ b/src/Catalogue.cxx
@@ -168,6 +168,7 @@ int Scintilla_LinkLexers() {
LINK_LEXER(lmRegistry);
LINK_LEXER(lmRuby);
LINK_LEXER(lmRust);
+ LINK_LEXER(lmSAS);
LINK_LEXER(lmScriptol);
LINK_LEXER(lmSmalltalk);
LINK_LEXER(lmSML);
@@ -176,6 +177,7 @@ int Scintilla_LinkLexers() {
LINK_LEXER(lmSpice);
LINK_LEXER(lmSQL);
LINK_LEXER(lmSrec);
+ LINK_LEXER(lmStata);
LINK_LEXER(lmSTTXT);
LINK_LEXER(lmTACL);
LINK_LEXER(lmTADS3);
diff --git a/win32/scintilla.mak b/win32/scintilla.mak
index 8a760fa39..cdda0d0ec 100644
--- a/win32/scintilla.mak
+++ b/win32/scintilla.mak
@@ -189,6 +189,7 @@ LEXOBJS=\
$(DIR_O)\LexRegistry.obj \
$(DIR_O)\LexRuby.obj \
$(DIR_O)\LexRust.obj \
+ $(DIR_O)\LexSAS.obj \
$(DIR_O)\LexScriptol.obj \
$(DIR_O)\LexSmalltalk.obj \
$(DIR_O)\LexSML.obj \
@@ -196,6 +197,7 @@ LEXOBJS=\
$(DIR_O)\LexSpecman.obj \
$(DIR_O)\LexSpice.obj \
$(DIR_O)\LexSQL.obj \
+ $(DIR_O)\LexStata.obj \
$(DIR_O)\LexSTTXT.obj \
$(DIR_O)\LexTACL.obj \
$(DIR_O)\LexTADS3.obj \
@@ -698,6 +700,8 @@ $(DIR_O)\LexRuby.obj: ..\lexers\LexRuby.cxx $(LEX_HEADERS)
$(DIR_O)\LexRust.obj: ..\lexers\LexRust.cxx $(LEX_HEADERS)
+$(DIR_O)\LexSAS.obj: ..\lexers\LexSAS.cxx $(LEX_HEADERS)
+
$(DIR_O)\LexScriptol.obj: ..\lexers\LexScriptol.cxx $(LEX_HEADERS)
$(DIR_O)\LexSmalltalk.obj: ..\lexers\LexSmalltalk.cxx $(LEX_HEADERS)
@@ -712,6 +716,8 @@ $(DIR_O)\LexSpice.obj: ..\lexers\LexSpice.cxx $(LEX_HEADERS)
$(DIR_O)\LexSQL.obj: ..\lexers\LexSQL.cxx $(LEX_HEADERS)
+$(DIR_O)\LexStata.obj: ..\lexers\LexStata.cxx $(LEX_HEADERS)
+
$(DIR_O)\LexSTTXT.obj: ..\lexers\LexSTTXT.cxx $(LEX_HEADERS)
$(DIR_O)\LexTACL.obj: ..\lexers\LexTACL.cxx $(LEX_HEADERS)