diff options
-rw-r--r-- | include/SciLexer.h | 14 | ||||
-rw-r--r-- | include/Scintilla.iface | 16 | ||||
-rw-r--r-- | lexers/LexRegistry.cxx | 416 | ||||
-rw-r--r-- | src/Catalogue.cxx | 1 | ||||
-rw-r--r-- | win32/scintilla.mak | 3 |
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) |