diff options
Diffstat (limited to 'lexers/LexRegistry.cxx')
| -rw-r--r-- | lexers/LexRegistry.cxx | 416 | 
1 files changed, 416 insertions, 0 deletions
| 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); + | 
