aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/SciLexer.h14
-rw-r--r--include/Scintilla.iface16
-rw-r--r--lexers/LexRegistry.cxx416
-rw-r--r--src/Catalogue.cxx1
-rw-r--r--win32/scintilla.mak3
5 files changed, 450 insertions, 0 deletions
diff --git a/include/SciLexer.h b/include/SciLexer.h
index 673acb55d..b45ed9474 100644
--- a/include/SciLexer.h
+++ b/include/SciLexer.h
@@ -127,6 +127,7 @@
#define SCLEX_DMAP 112
#define SCLEX_AS 113
#define SCLEX_DMIS 114
+#define SCLEX_REGISTRY 115
#define SCLEX_AUTOMATIC 1000
#define SCE_P_DEFAULT 0
#define SCE_P_COMMENTLINE 1
@@ -1717,6 +1718,19 @@
#define SCE_DMIS_UNSUPPORTED_MAJOR 7
#define SCE_DMIS_UNSUPPORTED_MINOR 8
#define SCE_DMIS_LABEL 9
+#define SCE_REG_DEFAULT 0
+#define SCE_REG_COMMENT 1
+#define SCE_REG_VALUENAME 2
+#define SCE_REG_STRING 3
+#define SCE_REG_HEXDIGIT 4
+#define SCE_REG_VALUETYPE 5
+#define SCE_REG_ADDEDKEY 6
+#define SCE_REG_DELETEDKEY 7
+#define SCE_REG_ESCAPED 8
+#define SCE_REG_KEYPATH_GUID 9
+#define SCE_REG_STRING_GUID 10
+#define SCE_REG_PARAMETER 11
+#define SCE_REG_OPERATOR 12
/* --Autogenerated -- end of section automatically generated from Scintilla.iface */
#endif
diff --git a/include/Scintilla.iface b/include/Scintilla.iface
index b0399e5ee..ec047f2d4 100644
--- a/include/Scintilla.iface
+++ b/include/Scintilla.iface
@@ -2699,6 +2699,7 @@ val SCLEX_RUST=111
val SCLEX_DMAP=112
val SCLEX_AS=113
val SCLEX_DMIS=114
+val SCLEX_REGISTRY=115
# When a lexer specifies its language as SCLEX_AUTOMATIC it receives a
# value assigned in sequence from SCLEX_AUTOMATIC+1.
@@ -4496,6 +4497,21 @@ val SCE_DMIS_MINORWORD=6
val SCE_DMIS_UNSUPPORTED_MAJOR=7
val SCE_DMIS_UNSUPPORTED_MINOR=8
val SCE_DMIS_LABEL=9
+# Lexical states for SCLEX_REGISTRY
+lex REG=SCLEX_REGISTRY SCE_REG_
+val SCE_REG_DEFAULT=0
+val SCE_REG_COMMENT=1
+val SCE_REG_VALUENAME=2
+val SCE_REG_STRING=3
+val SCE_REG_HEXDIGIT=4
+val SCE_REG_VALUETYPE=5
+val SCE_REG_ADDEDKEY=6
+val SCE_REG_DELETEDKEY=7
+val SCE_REG_ESCAPED=8
+val SCE_REG_KEYPATH_GUID=9
+val SCE_REG_STRING_GUID=10
+val SCE_REG_PARAMETER=11
+val SCE_REG_OPERATOR=12
# Events
diff --git a/lexers/LexRegistry.cxx b/lexers/LexRegistry.cxx
new file mode 100644
index 000000000..64b30d249
--- /dev/null
+++ b/lexers/LexRegistry.cxx
@@ -0,0 +1,416 @@
+// Scintilla source code edit control
+/**
+ * @file LexRegistry.cxx
+ * @date July 26 2014
+ * @brief Lexer for Windows registration files(.reg)
+ * @author nkmathew
+ *
+ * The License.txt file describes the conditions under which this software may be
+ * distributed.
+ *
+ */
+
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "ILexer.h"
+#include "Scintilla.h"
+#include "SciLexer.h"
+#include "WordList.h"
+#include "LexAccessor.h"
+#include "StyleContext.h"
+#include "CharacterSet.h"
+#include "LexerModule.h"
+#include "OptionSet.h"
+
+#ifdef SCI_NAMESPACE
+using namespace Scintilla;
+#endif
+
+static const char *const RegistryWordListDesc[] = {
+ 0
+};
+
+struct OptionsRegistry {
+ bool foldCompact;
+ bool fold;
+ OptionsRegistry() {
+ foldCompact = false;
+ fold = false;
+ }
+};
+
+struct OptionSetRegistry : public OptionSet<OptionsRegistry> {
+ OptionSetRegistry() {
+ DefineProperty("fold.compact", &OptionsRegistry::foldCompact);
+ DefineProperty("fold", &OptionsRegistry::fold);
+ DefineWordListSets(RegistryWordListDesc);
+ }
+};
+
+class LexerRegistry : public ILexer {
+ OptionsRegistry options;
+ OptionSetRegistry optSetRegistry;
+
+ static bool IsStringState(int state) {
+ return (state == SCE_REG_VALUENAME || state == SCE_REG_STRING);
+ }
+
+ static bool IsKeyPathState(int state) {
+ return (state == SCE_REG_ADDEDKEY || state == SCE_REG_DELETEDKEY);
+ }
+
+ static bool AtValueType(LexAccessor &styler, int start) {
+ int i = 0;
+ while (i < 10) {
+ i++;
+ char curr = styler.SafeGetCharAt(start+i, '\0');
+ if (curr == ':') {
+ return true;
+ } else if (!curr) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ static bool IsNextNonWhitespace(LexAccessor &styler, int start, char ch) {
+ int i = 0;
+ while (i < 100) {
+ i++;
+ char curr = styler.SafeGetCharAt(start+i, '\0');
+ char next = styler.SafeGetCharAt(start+i+1, '\0');
+ bool atEOL = (curr == '\r' && next != '\n') || (curr == '\n');
+ if (curr == ch) {
+ return true;
+ } else if (!isspacechar(curr) || atEOL) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ // Looks for the equal sign at the end of the string
+ static bool AtValueName(LexAccessor &styler, int start) {
+ bool atEOL = false;
+ int i = 0;
+ bool escaped = false;
+ while (!atEOL) {
+ i++;
+ char curr = styler.SafeGetCharAt(start+i, '\0');
+ char next = styler.SafeGetCharAt(start+i+1, '\0');
+ atEOL = (curr == '\r' && next != '\n') || (curr == '\n');
+ if (escaped) {
+ escaped = false;
+ continue;
+ }
+ escaped = curr == '\\';
+ if (curr == '"') {
+ return IsNextNonWhitespace(styler, start+i, '=');
+ } else if (!curr) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ static bool AtKeyPathEnd(LexAccessor &styler, int start) {
+ bool atEOL = false;
+ int i = 0;
+ while (!atEOL) {
+ i++;
+ char curr = styler.SafeGetCharAt(start+i, '\0');
+ char next = styler.SafeGetCharAt(start+i+1, '\0');
+ atEOL = (curr == '\r' && next != '\n') || (curr == '\n');
+ if (curr == ']' || !curr) {
+ // There's still at least one or more square brackets ahead
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static bool AtGUID(LexAccessor &styler, int start) {
+ int count = 8;
+ int portion = 0;
+ int offset = 1;
+ char digit = '\0';
+ while (portion < 5) {
+ int i = 0;
+ while (i < count) {
+ digit = styler.SafeGetCharAt(start+offset);
+ if (!(isxdigit(digit) || digit == '-')) {
+ return false;
+ }
+ offset++;
+ i++;
+ }
+ portion++;
+ count = (portion == 4) ? 13 : 5;
+ }
+ digit = styler.SafeGetCharAt(start+offset);
+ if (digit == '}') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+public:
+ LexerRegistry() {}
+ virtual ~LexerRegistry() {}
+ virtual int SCI_METHOD Version() const {
+ return lvOriginal;
+ }
+ virtual void SCI_METHOD Release() {
+ delete this;
+ }
+ virtual const char *SCI_METHOD PropertyNames() {
+ return optSetRegistry.PropertyNames();
+ }
+ virtual int SCI_METHOD PropertyType(const char *name) {
+ return optSetRegistry.PropertyType(name);
+ }
+ virtual const char *SCI_METHOD DescribeProperty(const char *name) {
+ return optSetRegistry.DescribeProperty(name);
+ }
+ virtual int SCI_METHOD PropertySet(const char *key, const char *val) {
+ if (optSetRegistry.PropertySet(&options, key, val)) {
+ return 0;
+ }
+ return -1;
+ }
+ virtual int SCI_METHOD WordListSet(int, const char *) {
+ return -1;
+ }
+ virtual void *SCI_METHOD PrivateCall(int, void *) {
+ return 0;
+ }
+ static ILexer *LexerFactoryRegistry() {
+ return new LexerRegistry;
+ }
+ virtual const char *SCI_METHOD DescribeWordListSets() {
+ return optSetRegistry.DescribeWordListSets();
+ }
+ virtual void SCI_METHOD Lex(unsigned startPos,
+ int length,
+ int initStyle,
+ IDocument *pAccess);
+ virtual void SCI_METHOD Fold(unsigned startPos,
+ int length,
+ int initStyle,
+ IDocument *pAccess);
+};
+
+void SCI_METHOD LexerRegistry::Lex(unsigned startPos,
+ int length,
+ int initStyle,
+ IDocument *pAccess) {
+ int beforeGUID = SCE_REG_DEFAULT;
+ int beforeEscape = SCE_REG_DEFAULT;
+ CharacterSet setOperators = CharacterSet(CharacterSet::setNone, "-,.=:\\@()");
+ LexAccessor styler(pAccess);
+ StyleContext context(startPos, length, initStyle, styler);
+ bool highlight = true;
+ bool afterEqualSign = false;
+ while (context.More()) {
+ if (context.atLineStart) {
+ int currPos = static_cast<int>(context.currentPos);
+ bool continued = styler[currPos-3] == '\\';
+ highlight = continued ? true : false;
+ }
+ switch (context.state) {
+ case SCE_REG_COMMENT:
+ if (context.atLineEnd) {
+ context.SetState(SCE_REG_DEFAULT);
+ }
+ break;
+ case SCE_REG_VALUENAME:
+ case SCE_REG_STRING: {
+ int currPos = static_cast<int>(context.currentPos);
+ if (context.ch == '"') {
+ context.ForwardSetState(SCE_REG_DEFAULT);
+ } else if (context.ch == '\\') {
+ beforeEscape = context.state;
+ context.SetState(SCE_REG_ESCAPED);
+ context.Forward();
+ } else if (context.ch == '{') {
+ if (AtGUID(styler, currPos)) {
+ beforeGUID = context.state;
+ context.SetState(SCE_REG_STRING_GUID);
+ }
+ }
+ if (context.state == SCE_REG_STRING &&
+ context.ch == '%' &&
+ (isdigit(context.chNext) || context.chNext == '*')) {
+ context.SetState(SCE_REG_PARAMETER);
+ }
+ }
+ break;
+ case SCE_REG_PARAMETER:
+ context.ForwardSetState(SCE_REG_STRING);
+ if (context.ch == '"') {
+ context.ForwardSetState(SCE_REG_DEFAULT);
+ }
+ break;
+ case SCE_REG_VALUETYPE:
+ if (context.ch == ':') {
+ context.SetState(SCE_REG_DEFAULT);
+ afterEqualSign = false;
+ }
+ break;
+ case SCE_REG_HEXDIGIT:
+ case SCE_REG_OPERATOR:
+ context.SetState(SCE_REG_DEFAULT);
+ break;
+ case SCE_REG_DELETEDKEY:
+ case SCE_REG_ADDEDKEY: {
+ int currPos = static_cast<int>(context.currentPos);
+ if (context.ch == ']' && AtKeyPathEnd(styler, currPos)) {
+ context.ForwardSetState(SCE_REG_DEFAULT);
+ } else if (context.ch == '{') {
+ if (AtGUID(styler, currPos)) {
+ beforeGUID = context.state;
+ context.SetState(SCE_REG_KEYPATH_GUID);
+ }
+ }
+ }
+ break;
+ case SCE_REG_ESCAPED:
+ if (context.ch == '"') {
+ context.SetState(beforeEscape);
+ context.ForwardSetState(SCE_REG_DEFAULT);
+ } else if (context.ch == '\\') {
+ context.Forward();
+ } else {
+ context.SetState(beforeEscape);
+ beforeEscape = SCE_REG_DEFAULT;
+ }
+ break;
+ case SCE_REG_STRING_GUID:
+ case SCE_REG_KEYPATH_GUID: {
+ if (context.ch == '}') {
+ context.ForwardSetState(beforeGUID);
+ beforeGUID = SCE_REG_DEFAULT;
+ }
+ int currPos = static_cast<int>(context.currentPos);
+ if (context.ch == '"' && IsStringState(context.state)) {
+ context.ForwardSetState(SCE_REG_DEFAULT);
+ } else if (context.ch == ']' &&
+ AtKeyPathEnd(styler, currPos) &&
+ IsKeyPathState(context.state)) {
+ context.ForwardSetState(SCE_REG_DEFAULT);
+ } else if (context.ch == '\\' && IsStringState(context.state)) {
+ beforeEscape = context.state;
+ context.SetState(SCE_REG_ESCAPED);
+ context.Forward();
+ }
+ }
+ break;
+ }
+ // Determine if a new state should be entered.
+ if (context.state == SCE_REG_DEFAULT) {
+ int currPos = static_cast<int>(context.currentPos);
+ if (context.ch == ';') {
+ context.SetState(SCE_REG_COMMENT);
+ } else if (context.ch == '"') {
+ if (AtValueName(styler, currPos)) {
+ context.SetState(SCE_REG_VALUENAME);
+ } else {
+ context.SetState(SCE_REG_STRING);
+ }
+ } else if (context.ch == '[') {
+ if (IsNextNonWhitespace(styler, currPos, '-')) {
+ context.SetState(SCE_REG_DELETEDKEY);
+ } else {
+ context.SetState(SCE_REG_ADDEDKEY);
+ }
+ } else if (context.ch == '=') {
+ afterEqualSign = true;
+ highlight = true;
+ } else if (afterEqualSign) {
+ bool wordStart = isalpha(context.ch) && !isalpha(context.chPrev);
+ if (wordStart && AtValueType(styler, currPos)) {
+ context.SetState(SCE_REG_VALUETYPE);
+ }
+ } else if (isxdigit(context.ch) && highlight) {
+ context.SetState(SCE_REG_HEXDIGIT);
+ }
+ highlight = (context.ch == '@') ? true : highlight;
+ if (setOperators.Contains(context.ch) && highlight) {
+ context.SetState(SCE_REG_OPERATOR);
+ }
+ }
+ context.Forward();
+ }
+ context.Complete();
+}
+
+// Folding similar to that of FoldPropsDoc in LexOthers
+void SCI_METHOD LexerRegistry::Fold(unsigned startPos,
+ int length,
+ int,
+ IDocument *pAccess) {
+ if (!options.fold) {
+ return;
+ }
+ LexAccessor styler(pAccess);
+ int currLine = styler.GetLine(startPos);
+ int visibleChars = 0;
+ unsigned endPos = startPos + length;
+ bool atKeyPath = false;
+ for (unsigned i = startPos; i < endPos; i++) {
+ atKeyPath = IsKeyPathState(styler.StyleAt(i)) ? true : atKeyPath;
+ char curr = styler.SafeGetCharAt(i);
+ char next = styler.SafeGetCharAt(i+1);
+ bool atEOL = (curr == '\r' && next != '\n') || (curr == '\n');
+ if (atEOL || i == (endPos-1)) {
+ int level = SC_FOLDLEVELBASE;
+ if (currLine > 0) {
+ int prevLevel = styler.LevelAt(currLine-1);
+ if (prevLevel & SC_FOLDLEVELHEADERFLAG) {
+ level += 1;
+ } else {
+ level = prevLevel;
+ }
+ }
+ if (!visibleChars && options.foldCompact) {
+ level |= SC_FOLDLEVELWHITEFLAG;
+ } else if (atKeyPath) {
+ level = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
+ }
+ if (level != styler.LevelAt(currLine)) {
+ styler.SetLevel(currLine, level);
+ }
+ currLine++;
+ visibleChars = 0;
+ atKeyPath = false;
+ }
+ if (!isspacechar(curr)) {
+ visibleChars++;
+ }
+ }
+
+ // Make the folding reach the last line in the file
+ int level = SC_FOLDLEVELBASE;
+ if (currLine > 0) {
+ int prevLevel = styler.LevelAt(currLine-1);
+ if (prevLevel & SC_FOLDLEVELHEADERFLAG) {
+ level += 1;
+ } else {
+ level = prevLevel;
+ }
+ }
+ styler.SetLevel(currLine, level);
+}
+
+LexerModule lmRegistry(SCLEX_REGISTRY,
+ LexerRegistry::LexerFactoryRegistry,
+ "registry",
+ RegistryWordListDesc);
+
diff --git a/src/Catalogue.cxx b/src/Catalogue.cxx
index ac1fc3818..097fe7659 100644
--- a/src/Catalogue.cxx
+++ b/src/Catalogue.cxx
@@ -163,6 +163,7 @@ int Scintilla_LinkLexers() {
LINK_LEXER(lmPython);
LINK_LEXER(lmR);
LINK_LEXER(lmREBOL);
+ LINK_LEXER(lmRegistry);
LINK_LEXER(lmRuby);
LINK_LEXER(lmRust);
LINK_LEXER(lmScriptol);
diff --git a/win32/scintilla.mak b/win32/scintilla.mak
index 2febf86f3..3d73ba3ce 100644
--- a/win32/scintilla.mak
+++ b/win32/scintilla.mak
@@ -166,6 +166,7 @@ LEXOBJS=\
$(DIR_O)\LexPython.obj \
$(DIR_O)\LexR.obj \
$(DIR_O)\LexRebol.obj \
+ $(DIR_O)\LexRegistry.obj \
$(DIR_O)\LexRuby.obj \
$(DIR_O)\LexRust.obj \
$(DIR_O)\LexScriptol.obj \
@@ -592,6 +593,8 @@ $(DIR_O)\LexR.obj: ..\lexers\LexR.cxx $(LEX_HEADERS)
$(DIR_O)\LexRebol.obj: ..\lexers\LexRebol.cxx $(LEX_HEADERS)
+$(DIR_O)\LexRegistry.obj: ..\lexers\LexRegistry.cxx $(LEX_HEADERS)
+
$(DIR_O)\LexRuby.obj: ..\lexers\LexRuby.cxx $(LEX_HEADERS)
$(DIR_O)\LexRust.obj: ..\lexers\LexRust.cxx $(LEX_HEADERS)