diff -r 8d56eaef4f0a include/ILexer.h
--- a/include/ILexer.h	Mon Jun 19 12:10:18 2017 +1000
+++ b/include/ILexer.h	Mon Jun 19 20:21:57 2017 +1000
@@ -20,7 +20,7 @@
 	#define SCI_METHOD
 #endif
 
-enum { dvOriginal=0, dvLineEnd=1 };
+enum { dvRelease4=2 };
 
 class IDocument {
 public:
@@ -35,7 +35,7 @@
 	virtual int SCI_METHOD SetLevel(Sci_Position line, int level) = 0;
 	virtual int SCI_METHOD GetLineState(Sci_Position line) const = 0;
 	virtual int SCI_METHOD SetLineState(Sci_Position line, int state) = 0;
-	virtual void SCI_METHOD StartStyling(Sci_Position position, char mask) = 0;
+	virtual void SCI_METHOD StartStyling(Sci_Position position) = 0;
 	virtual bool SCI_METHOD SetStyleFor(Sci_Position length, char style) = 0;
 	virtual bool SCI_METHOD SetStyles(Sci_Position length, const char *styles) = 0;
 	virtual void SCI_METHOD DecorationSetCurrentIndicator(int indicator) = 0;
@@ -45,16 +45,12 @@
 	virtual bool SCI_METHOD IsDBCSLeadByte(char ch) const = 0;
 	virtual const char * SCI_METHOD BufferPointer() = 0;
 	virtual int SCI_METHOD GetLineIndentation(Sci_Position line) = 0;
-};
-
-class IDocumentWithLineEnd : public IDocument {
-public:
 	virtual Sci_Position SCI_METHOD LineEnd(Sci_Position line) const = 0;
 	virtual Sci_Position SCI_METHOD GetRelativePosition(Sci_Position positionStart, Sci_Position characterOffset) const = 0;
 	virtual int SCI_METHOD GetCharacterAndWidth(Sci_Position position, Sci_Position *pWidth) const = 0;
 };
 
-enum { lvOriginal=0, lvSubStyles=1 };
+enum { lvRelease4=2 };
 
 class ILexer {
 public:
@@ -69,10 +65,6 @@
 	virtual void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) = 0;
 	virtual void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) = 0;
 	virtual void * SCI_METHOD PrivateCall(int operation, void *pointer) = 0;
-};
-
-class ILexerWithSubStyles : public ILexer {
-public:
 	virtual int SCI_METHOD LineEndTypesSupported() = 0;
 	virtual int SCI_METHOD AllocateSubStyles(int styleBase, int numberStyles) = 0;
 	virtual int SCI_METHOD SubStylesStart(int styleBase) = 0;
@@ -83,6 +75,10 @@
 	virtual void SCI_METHOD SetIdentifiers(int style, const char *identifiers) = 0;
 	virtual int SCI_METHOD DistanceToSecondaryStyles() = 0;
 	virtual const char * SCI_METHOD GetSubStyleBases() = 0;
+	virtual int SCI_METHOD MaximumNamedStyle() = 0;
+	virtual const char * SCI_METHOD NameOfStyle(int style) = 0;
+	virtual const char * SCI_METHOD TagsOfStyle(int style) = 0;
+	virtual const char * SCI_METHOD DescriptionOfStyle(int style) = 0;
 };
 
 class ILoader {
diff -r 8d56eaef4f0a include/Sci_Position.h
--- a/include/Sci_Position.h	Mon Jun 19 12:10:18 2017 +1000
+++ b/include/Sci_Position.h	Mon Jun 19 20:21:57 2017 +1000
@@ -9,11 +9,13 @@
 #ifndef SCI_POSITION_H
 #define SCI_POSITION_H
 
+#include <stddef.h>
+
 // Basic signed type used throughout interface
-typedef int Sci_Position;
+typedef ptrdiff_t Sci_Position;
 
 // Unsigned variant used for ILexer::Lex and ILexer::Fold
-typedef unsigned int Sci_PositionU;
+typedef size_t Sci_PositionU;
 
 // For Sci_CharacterRange  which is defined as long to be compatible with Win32 CHARRANGE
 typedef long Sci_PositionCR;
diff -r 8d56eaef4f0a include/Scintilla.h
--- a/include/Scintilla.h	Mon Jun 19 12:10:18 2017 +1000
+++ b/include/Scintilla.h	Mon Jun 19 20:21:57 2017 +1000
@@ -1010,6 +1010,10 @@
 #define SCI_SETIDENTIFIERS 4024
 #define SCI_DISTANCETOSECONDARYSTYLES 4025
 #define SCI_GETSUBSTYLEBASES 4026
+#define SCI_GETMAXIMUMNAMEDSTYLE 4029
+#define SCI_NAMEOFSTYLE 4030
+#define SCI_TAGSOFSTYLE 4031
+#define SCI_DESCRIPTIONOFSTYLE 4032
 #define SC_MOD_INSERTTEXT 0x1
 #define SC_MOD_DELETETEXT 0x2
 #define SC_MOD_CHANGESTYLE 0x4
diff -r 8d56eaef4f0a include/Scintilla.iface
--- a/include/Scintilla.iface	Mon Jun 19 12:10:18 2017 +1000
+++ b/include/Scintilla.iface	Mon Jun 19 20:21:57 2017 +1000
@@ -2709,6 +2709,21 @@
 # Result is NUL-terminated.
 get int GetSubStyleBases=4026(, stringresult styles)
 
+# Retrieve the maximum named style for the lexer.
+get int GetMaximumNamedStyle=4029(,)
+
+# Retrieve the name of a style.
+# Result is NUL-terminated.
+fun int NameOfStyle=4030(int style, stringresult names)
+
+# Retrieve a ' ' separated list of style tags like "literal quoted string".
+# Result is NUL-terminated.
+fun int TagsOfStyle=4031(int style, stringresult names)
+
+# Retrieve a description of a style.
+# Result is NUL-terminated.
+fun int DescriptionOfStyle=4032(int style, stringresult names)
+
 # Notifications
 # Type of modification and the action which caused the modification.
 # These are defined as a bit mask to make it easy to specify which notifications are wanted.
diff -r 8d56eaef4f0a lexers/LexAsm.cxx
--- a/lexers/LexAsm.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexAsm.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -30,6 +30,7 @@
 #include "CharacterSet.h"
 #include "LexerModule.h"
 #include "OptionSet.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -139,7 +140,7 @@
 	}
 };
 
-class LexerAsm : public ILexer {
+class LexerAsm : public DefaultLexer {
 	WordList cpuInstruction;
 	WordList mathInstruction;
 	WordList registers;
@@ -161,7 +162,7 @@
 		delete this;
 	}
 	int SCI_METHOD Version() const override {
-		return lvOriginal;
+		return lvRelease4;
 	}
 	const char * SCI_METHOD PropertyNames() override {
 		return osAsm.PropertyNames();
diff -r 8d56eaef4f0a lexers/LexBaan.cxx
--- a/lexers/LexBaan.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexBaan.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -34,6 +34,7 @@
 #include "CharacterSet.h"
 #include "LexerModule.h"
 #include "OptionSet.h"
+#include "DefaultLexer.h"
 
 # ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -381,7 +382,7 @@
 
 }
 
-class LexerBaan : public ILexer {
+class LexerBaan : public DefaultLexer {
 	WordListAbridged keywords;
 	WordListAbridged keywords2;
 	WordListAbridged keywords3;
@@ -401,7 +402,7 @@
 	}
 
 	int SCI_METHOD Version() const override {
-		return lvOriginal;
+		return lvRelease4;
 	}
 
 	void SCI_METHOD Release() override {
diff -r 8d56eaef4f0a lexers/LexBasic.cxx
--- a/lexers/LexBasic.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexBasic.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -37,6 +37,7 @@
 #include "CharacterSet.h"
 #include "LexerModule.h"
 #include "OptionSet.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -226,7 +227,7 @@
 	}
 };
 
-class LexerBasic : public ILexer {
+class LexerBasic : public DefaultLexer {
 	char comment_char;
 	int (*CheckFoldPoint)(char const *, int &);
 	WordList keywordlists[4];
@@ -244,7 +245,7 @@
 		delete this;
 	}
 	int SCI_METHOD Version() const override {
-		return lvOriginal;
+		return lvRelease4;
 	}
 	const char * SCI_METHOD PropertyNames() override {
 		return osBasic.PropertyNames();
diff -r 8d56eaef4f0a lexers/LexCPP.cxx
--- a/lexers/LexCPP.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexCPP.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -432,9 +432,41 @@
 
 const char styleSubable[] = {SCE_C_IDENTIFIER, SCE_C_COMMENTDOCKEYWORD, 0};
 
+LexicalClass lexicalClasses[] = {
+	// Lexer cpp SCLEX_CPP SCE_C_:
+	0, "SCE_C_DEFAULT", "default whitespace", "White space",
+	1, "SCE_C_COMMENT", "comment", "Comment: /* */.",
+	2, "SCE_C_COMMENTLINE", "comment line", "Line Comment: //.",
+	3, "SCE_C_COMMENTDOC", "comment documentation", "Doc comment: block comments beginning with /** or /*!",
+	4, "SCE_C_NUMBER", "literal numeric", "Number",
+	5, "SCE_C_WORD", "keyword", "Keyword",
+	6, "SCE_C_STRING", "literal string", "Double quoted string",
+	7, "SCE_C_CHARACTER", "literal string character", "Single quoted string",
+	8, "SCE_C_UUID", "literal uuid", "UUIDs (only in IDL)",
+	9, "SCE_C_PREPROCESSOR", "preprocessor", "Preprocessor",
+	10, "SCE_C_OPERATOR", "operator", "Operators",
+	11, "SCE_C_IDENTIFIER", "identifier", "Identifiers",
+	12, "SCE_C_STRINGEOL", "error literal line string", "End of line where string is not closed",
+	13, "SCE_C_VERBATIM", "literal string multiline raw", "Verbatim strings for C#",
+	14, "SCE_C_REGEX", "literal regex", "Regular expressions for JavaScript",
+	15, "SCE_C_COMMENTLINEDOC", "comment documentation line", "Doc Comment Line: line comments beginning with /// or //!.",
+	16, "SCE_C_WORD2", "identifier", "Keywords2",
+	17, "SCE_C_COMMENTDOCKEYWORD", "comment documentation keyword", "Comment keyword",
+	18, "SCE_C_COMMENTDOCKEYWORDERROR", "error comment documentation keyword", "Comment keyword error",
+	19, "SCE_C_GLOBALCLASS", "identifier", "Global class",
+	20, "SCE_C_STRINGRAW", "literal string multiline raw", "Raw strings for C++0x",
+	21, "SCE_C_TRIPLEVERBATIM", "literal string multiline raw", "Triple-quoted strings for Vala",
+	22, "SCE_C_HASHQUOTEDSTRING", "literal string", "Hash-quoted strings for Pike",
+	23, "SCE_C_PREPROCESSORCOMMENT", "comment preprocessor", "Preprocessor stream comment",
+	24, "SCE_C_PREPROCESSORCOMMENTDOC", "comment preprocessor documentation", "Preprocessor stream doc comment",
+	25, "SCE_C_USERLITERAL", "literal", "User defined literals",
+	26, "SCE_C_TASKMARKER", "comment taskmarker", "Task Marker",
+	27, "SCE_C_ESCAPESEQUENCE", "literal string escapesequence", "Escape sequence",
+};
+
 }
 
-class LexerCPP : public ILexerWithSubStyles {
+class LexerCPP : public ILexer {
 	bool caseSensitive;
 	CharacterSet setWord;
 	CharacterSet setNegationOp;
@@ -489,7 +521,7 @@
 		delete this;
 	}
 	int SCI_METHOD Version() const override {
-		return lvSubStyles;
+		return lvRelease4;
 	}
 	const char * SCI_METHOD PropertyNames() override {
 		return osCPP.PropertyNames();
@@ -546,6 +578,19 @@
 		return styleSubable;
 	}
 
+	int SCI_METHOD MaximumNamedStyle() {
+		return (sizeof(lexicalClasses) / sizeof(lexicalClasses[0])) - 1;
+	}
+	const char * SCI_METHOD NameOfStyle(int style) {
+		return (style < MaximumNamedStyle()) ? lexicalClasses[style].name : "";
+	}
+	const char * SCI_METHOD TagsOfStyle(int style) {
+		return (style < MaximumNamedStyle()) ? lexicalClasses[style].tags : "";
+	}
+	const char * SCI_METHOD DescriptionOfStyle(int style) {
+		return (style < MaximumNamedStyle()) ? lexicalClasses[style].description : "";
+	}
+
 	static ILexer *LexerFactoryCPP() {
 		return new LexerCPP(true);
 	}
diff -r 8d56eaef4f0a lexers/LexD.cxx
--- a/lexers/LexD.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexD.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -27,6 +27,7 @@
 #include "CharacterSet.h"
 #include "LexerModule.h"
 #include "OptionSet.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -145,7 +146,7 @@
 	}
 };
 
-class LexerD : public ILexer {
+class LexerD : public DefaultLexer {
 	bool caseSensitive;
 	WordList keywords;
 	WordList keywords2;
@@ -166,7 +167,7 @@
 		delete this;
 	}
 	int SCI_METHOD Version() const override {
-		return lvOriginal;
+		return lvRelease4;
 	}
 	const char * SCI_METHOD PropertyNames() override {
 		return osD.PropertyNames();
diff -r 8d56eaef4f0a lexers/LexDMIS.cxx
--- a/lexers/LexDMIS.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexDMIS.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -21,6 +21,7 @@
 #include "StyleContext.h"
 #include "CharacterSet.h"
 #include "LexerModule.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -38,7 +39,7 @@
 };
 
 
-class LexerDMIS : public ILexer
+class LexerDMIS : public DefaultLexer
 {
 	private:
 		char *m_wordListSets;
@@ -57,7 +58,7 @@
 		virtual ~LexerDMIS(void);
 
 		int SCI_METHOD Version() const override {
-			return lvOriginal;
+			return lvRelease4;
 		}
 
 		void SCI_METHOD Release() override {
diff -r 8d56eaef4f0a lexers/LexEDIFACT.cxx
--- a/lexers/LexEDIFACT.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexEDIFACT.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -18,12 +18,13 @@
 
 #include "LexAccessor.h"
 #include "LexerModule.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
 #endif
 
-class LexerEDIFACT : public ILexer
+class LexerEDIFACT : public DefaultLexer
 {
 public:
 	LexerEDIFACT();
@@ -35,7 +36,7 @@
 
 	int SCI_METHOD Version() const override
 	{
-		return lvOriginal;
+		return lvRelease4;
 	}
 	void SCI_METHOD Release() override
 	{
@@ -124,7 +125,7 @@
 
 	// Style buffer, so we're not issuing loads of notifications
 	LexAccessor styler (pAccess);
-	pAccess->StartStyling(posCurrent, '\377');
+	pAccess->StartStyling(posCurrent);
 	styler.StartSegment(posCurrent);
 	Sci_Position posSegmentStart = -1;
 
@@ -187,7 +188,7 @@
 	if (posSegmentStart == -1)
 		return;
 
-	pAccess->StartStyling(posSegmentStart, -1);
+	pAccess->StartStyling(posSegmentStart);
 	pAccess->SetStyleFor(posFinish - posSegmentStart, SCE_EDI_BADSEGMENT);
 }
 
diff -r 8d56eaef4f0a lexers/LexHaskell.cxx
--- a/lexers/LexHaskell.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexHaskell.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -41,6 +41,7 @@
 #include "CharacterCategory.h"
 #include "LexerModule.h"
 #include "OptionSet.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -269,7 +270,7 @@
    }
 };
 
-class LexerHaskell : public ILexer {
+class LexerHaskell : public DefaultLexer {
    bool literate;
    Sci_Position firstImportLine;
    int firstImportIndent;
@@ -401,7 +402,8 @@
    }
 
    int SCI_METHOD Version() const override {
-      return lvOriginal;
+
+      return lvRelease4;
    }
 
    const char * SCI_METHOD PropertyNames() override {
diff -r 8d56eaef4f0a lexers/LexJSON.cxx
--- a/lexers/LexJSON.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexJSON.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -27,6 +27,7 @@
 #include "CharacterSet.h"
 #include "LexerModule.h"
 #include "OptionSet.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -128,7 +129,7 @@
 	}
 };
 
-class LexerJSON : public ILexer {
+class LexerJSON : public DefaultLexer {
 	OptionsJSON options;
 	OptionSetJSON optSetJSON;
 	EscapeSequence escapeSeq;
@@ -209,7 +210,7 @@
 	}
 	virtual ~LexerJSON() {}
 	int SCI_METHOD Version() const override {
-		return lvOriginal;
+		return lvRelease4;
 	}
 	void SCI_METHOD Release() override {
 		delete this;
diff -r 8d56eaef4f0a lexers/LexLaTeX.cxx
--- a/lexers/LexLaTeX.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexLaTeX.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -26,6 +26,7 @@
 #include "StyleContext.h"
 #include "CharacterSet.h"
 #include "LexerModule.h"
+#include "DefaultLexer.h"
 #include "LexerBase.h"
 
 #ifdef SCI_NAMESPACE
diff -r 8d56eaef4f0a lexers/LexLua.cxx
--- a/lexers/LexLua.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexLua.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -18,6 +18,7 @@
 #include "Scintilla.h"
 #include "SciLexer.h"
 
+#include "StringCopy.h"
 #include "WordList.h"
 #include "LexAccessor.h"
 #include "Accessor.h"
@@ -433,4 +434,33 @@
 	0
 };
 
-LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc, luaWordListDesc);
+namespace {
+
+LexicalClass lexicalClasses[] = {
+	// Lexer lua SCLEX_LUA SCE_LUA_:
+	0, "SCE_LUA_DEFAULT", "default whitespace", "White space: Visible only in View Whitespace mode (or if it has a back colour)",
+	1, "SCE_LUA_COMMENT", "comment", "Block comment (Lua 5.0)",
+	2, "SCE_LUA_COMMENTLINE", "comment line", "Line comment",
+	3, "SCE_LUA_COMMENTDOC", "unused comment documentation", "Doc comment -- Not used in Lua (yet?)",
+	4, "SCE_LUA_NUMBER", "literal numeric", "Number",
+	5, "SCE_LUA_WORD", "keyword", "Keyword",
+	6, "SCE_LUA_STRING", "literal string", "(Double quoted) String",
+	7, "SCE_LUA_CHARACTER", "literal string character", "Character (Single quoted string)",
+	8, "SCE_LUA_LITERALSTRING", "literal string", "Literal string",
+	9, "SCE_LUA_PREPROCESSOR", "preprocessor", "Preprocessor (obsolete in Lua 4.0 and up)",
+	10, "SCE_LUA_OPERATOR", "operator", "Operators",
+	11, "SCE_LUA_IDENTIFIER", "identifier", "Identifier (everything else...)",
+	12, "SCE_LUA_STRINGEOL", "error literal string", "End of line where string is not closed",
+	13, "SCE_LUA_WORD2", "identifier", "Other keywords",
+	14, "SCE_LUA_WORD3", "identifier", "Other keywords",
+	15, "SCE_LUA_WORD4", "identifier", "Other keywords",
+	16, "SCE_LUA_WORD5", "identifier", "Other keywords",
+	17, "SCE_LUA_WORD6", "identifier", "Other keywords",
+	18, "SCE_LUA_WORD7", "identifier", "Other keywords",
+	19, "SCE_LUA_WORD8", "identifier", "Other keywords",
+	20, "SCE_LUA_LABEL", "label", "Labels",
+};
+
+}
+
+LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc, luaWordListDesc, lexicalClasses, ELEMENTS(lexicalClasses));
diff -r 8d56eaef4f0a lexers/LexPerl.cxx
--- a/lexers/LexPerl.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexPerl.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -27,6 +27,7 @@
 #include "CharacterSet.h"
 #include "LexerModule.h"
 #include "OptionSet.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -398,7 +399,7 @@
 	}
 };
 
-class LexerPerl : public ILexer {
+class LexerPerl : public DefaultLexer {
 	CharacterSet setWordStart;
 	CharacterSet setWord;
 	CharacterSet setSpecialVar;
@@ -419,7 +420,7 @@
 		delete this;
 	}
 	int SCI_METHOD Version() const override {
-		return lvOriginal;
+		return lvRelease4;
 	}
 	const char *SCI_METHOD PropertyNames() override {
 		return osPerl.PropertyNames();
diff -r 8d56eaef4f0a lexers/LexProgress.cxx
--- a/lexers/LexProgress.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexProgress.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -38,6 +38,7 @@
 #include "LexerModule.h"
 #include "OptionSet.h"
 #include "SparseState.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -122,7 +123,7 @@
    };
 }
 
-class LexerABL : public ILexer {
+class LexerABL : public DefaultLexer {
    CharacterSet setWord;
    CharacterSet setNegationOp;
    CharacterSet setArithmethicOp;
@@ -149,7 +150,7 @@
       delete this;
    }
    int SCI_METHOD Version() const override {
-      return lvOriginal;
+      return lvRelease4;
    }
    const char * SCI_METHOD PropertyNames() override {
       return osABL.PropertyNames();
diff -r 8d56eaef4f0a lexers/LexPython.cxx
--- a/lexers/LexPython.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexPython.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -30,6 +30,7 @@
 #include "LexerModule.h"
 #include "OptionSet.h"
 #include "SubStyles.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -308,9 +309,33 @@
 
 const char styleSubable[] = { SCE_P_IDENTIFIER, 0 };
 
+LexicalClass lexicalClasses[] = {
+	// Lexer python SCLEX_PYTHON SCE_P_:
+	0, "SCE_P_DEFAULT", "default whitespace", "White space",
+	1, "SCE_P_COMMENTLINE", "comment line", "Comment",
+	2, "SCE_P_NUMBER", "literal numeric", "Number",
+	3, "SCE_P_STRING", "literal string", "String",
+	4, "SCE_P_CHARACTER", "literal string character", "Single quoted string",
+	5, "SCE_P_WORD", "keyword", "Keyword",
+	6, "SCE_P_TRIPLE", "literal string", "Triple quotes",
+	7, "SCE_P_TRIPLEDOUBLE", "literal string", "Triple double quotes",
+	8, "SCE_P_CLASSNAME", "identifier", "Class name definition",
+	9, "SCE_P_DEFNAME", "identifier", "Function or method name definition",
+	10, "SCE_P_OPERATOR", "operator", "Operators",
+	11, "SCE_P_IDENTIFIER", "identifier", "Identifiers",
+	12, "SCE_P_COMMENTBLOCK", "comment", "Comment-blocks",
+	13, "SCE_P_STRINGEOL", "error literal string", "End of line where string is not closed",
+	14, "SCE_P_WORD2", "identifier", "Highlighted identifiers",
+	15, "SCE_P_DECORATOR", "", "Decorators",
+	16, "SCE_P_FSTRING", "literal string", "F-String",
+	17, "SCE_P_FCHARACTER", "literal string character", "Single quoted f-string",
+	18, "SCE_P_FTRIPLE", "literal string", "Triple quoted f-string",
+	19, "SCE_P_FTRIPLEDOUBLE", "literal string", "Triple double quoted f-string",
+};
+
 }
 
-class LexerPython : public ILexerWithSubStyles {
+class LexerPython : public DefaultLexer {
 	WordList keywords;
 	WordList keywords2;
 	OptionsPython options;
@@ -320,6 +345,7 @@
 	std::map<int, std::vector<SingleFStringExpState> > ftripleStateAtEol;
 public:
 	explicit LexerPython() :
+		DefaultLexer(lexicalClasses, ELEMENTS(lexicalClasses)),
 		subStyles(styleSubable, 0x80, 0x40, 0) {
 	}
 	virtual ~LexerPython() {
@@ -328,7 +354,7 @@
 		delete this;
 	}
 	int SCI_METHOD Version() const override {
-		return lvSubStyles;
+		return lvRelease4;
 	}
 	const char *SCI_METHOD PropertyNames() override {
 		return osPython.PropertyNames();
diff -r 8d56eaef4f0a lexers/LexRegistry.cxx
--- a/lexers/LexRegistry.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexRegistry.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -27,6 +27,7 @@
 #include "CharacterSet.h"
 #include "LexerModule.h"
 #include "OptionSet.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -53,7 +54,7 @@
 	}
 };
 
-class LexerRegistry : public ILexer {
+class LexerRegistry : public DefaultLexer {
 	OptionsRegistry options;
 	OptionSetRegistry optSetRegistry;
 
@@ -165,7 +166,7 @@
 	LexerRegistry() {}
 	virtual ~LexerRegistry() {}
 	int SCI_METHOD Version() const override {
-		return lvOriginal;
+		return lvRelease4;
 	}
 	void SCI_METHOD Release() override {
 		delete this;
diff -r 8d56eaef4f0a lexers/LexRust.cxx
--- a/lexers/LexRust.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexRust.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -29,6 +29,7 @@
 #include "CharacterSet.h"
 #include "LexerModule.h"
 #include "OptionSet.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -116,7 +117,7 @@
 	}
 };
 
-class LexerRust : public ILexer {
+class LexerRust : public DefaultLexer {
 	WordList keywords[NUM_RUST_KEYWORD_LISTS];
 	OptionsRust options;
 	OptionSetRust osRust;
@@ -127,7 +128,7 @@
 		delete this;
 	}
 	int SCI_METHOD Version() const override {
-		return lvOriginal;
+		return lvRelease4;
 	}
 	const char * SCI_METHOD PropertyNames() override {
 		return osRust.PropertyNames();
diff -r 8d56eaef4f0a lexers/LexSQL.cxx
--- a/lexers/LexSQL.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexSQL.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -31,6 +31,7 @@
 #include "LexerModule.h"
 #include "OptionSet.h"
 #include "SparseState.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -302,14 +303,14 @@
 	}
 };
 
-class LexerSQL : public ILexer {
+class LexerSQL : public DefaultLexer {
 public :
 	LexerSQL() {}
 
 	virtual ~LexerSQL() {}
 
 	int SCI_METHOD Version () const override {
-		return lvOriginal;
+		return lvRelease4;
 	}
 
 	void SCI_METHOD Release() override {
diff -r 8d56eaef4f0a lexers/LexVerilog.cxx
--- a/lexers/LexVerilog.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexVerilog.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -31,6 +31,7 @@
 
 #include "OptionSet.h"
 #include "SubStyles.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -172,7 +173,7 @@
 
 }
 
-class LexerVerilog : public ILexerWithSubStyles {
+class LexerVerilog : public DefaultLexer {
 	CharacterSet setWord;
 	WordList keywords;
 	WordList keywords2;
@@ -218,7 +219,7 @@
 		}
 	virtual ~LexerVerilog() {}
 	int SCI_METHOD Version() const override {
-		return lvSubStyles;
+		return lvRelease4;
 	}
 	void SCI_METHOD Release() override {
 		delete this;
diff -r 8d56eaef4f0a lexers/LexVisualProlog.cxx
--- a/lexers/LexVisualProlog.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexers/LexVisualProlog.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -39,6 +39,7 @@
 #include "CharacterCategory.h"
 #include "LexerModule.h"
 #include "OptionSet.h"
+#include "DefaultLexer.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -64,7 +65,7 @@
     }
 };
 
-class LexerVisualProlog : public ILexer {
+class LexerVisualProlog : public DefaultLexer {
     WordList majorKeywords;
     WordList minorKeywords;
     WordList directiveKeywords;
@@ -80,7 +81,7 @@
         delete this;
     }
     int SCI_METHOD Version() const override {
-        return lvOriginal;
+        return lvRelease4;
     }
     const char * SCI_METHOD PropertyNames() override {
         return osVisualProlog.PropertyNames();
diff -r 8d56eaef4f0a lexlib/DefaultLexer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lexlib/DefaultLexer.h	Mon Jun 19 20:21:57 2017 +1000
@@ -0,0 +1,55 @@
+// Scintilla source code edit control
+/** @file DefaultLexer.h
+ ** A lexer base class with default empty implementations of methods. 
+ ** For lexers that do not support all features so do not need real implementations.
+ ** Implementation is temporarily in LexerBase.cxx.
+ **/
+// Copyright 2015 by Neil Hodgson <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#ifndef DEFAULTLEXER_H
+#define DEFAULTLEXER_H
+
+#ifdef SCI_NAMESPACE
+namespace Scintilla {
+#endif
+
+// A simple lexer with no state
+class DefaultLexer : public ILexer {
+	const LexicalClass *lexClasses;
+	size_t nClasses;
+public:
+	DefaultLexer(const LexicalClass *lexClasses_=nullptr, size_t nClasses_=0);
+	virtual ~DefaultLexer();
+	void SCI_METHOD Release();
+	int SCI_METHOD Version() const;
+	const char * SCI_METHOD PropertyNames();
+	int SCI_METHOD PropertyType(const char *name);
+	const char * SCI_METHOD DescribeProperty(const char *name);
+	Sci_Position SCI_METHOD PropertySet(const char *key, const char *val);
+	const char * SCI_METHOD DescribeWordListSets();
+	Sci_Position SCI_METHOD WordListSet(int n, const char *wl);
+	void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) = 0;
+	void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess);
+	void * SCI_METHOD PrivateCall(int operation, void *pointer);
+	int SCI_METHOD LineEndTypesSupported();
+	int SCI_METHOD AllocateSubStyles(int styleBase, int numberStyles);
+	int SCI_METHOD SubStylesStart(int styleBase);
+	int SCI_METHOD SubStylesLength(int styleBase);
+	int SCI_METHOD StyleFromSubStyle(int subStyle);
+	int SCI_METHOD PrimaryStyleFromStyle(int style);
+	void SCI_METHOD FreeSubStyles();
+	void SCI_METHOD SetIdentifiers(int style, const char *identifiers);
+	int SCI_METHOD DistanceToSecondaryStyles();
+	const char * SCI_METHOD GetSubStyleBases();
+	int SCI_METHOD MaximumNamedStyle();
+	const char * SCI_METHOD NameOfStyle(int style);
+	const char * SCI_METHOD DescriptionOfStyle(int style);
+	const char * SCI_METHOD TagsOfStyle(int style);
+};
+
+#ifdef SCI_NAMESPACE
+}
+#endif
+
+#endif
diff -r 8d56eaef4f0a lexlib/LexAccessor.h
--- a/lexlib/LexAccessor.h	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexlib/LexAccessor.h	Mon Jun 19 20:21:57 2017 +1000
@@ -79,11 +79,8 @@
 		}
 		return buf[position - startPos];
 	}
-	IDocumentWithLineEnd *MultiByteAccess() const {
-		if (documentVersion >= dvLineEnd) {
-			return static_cast<IDocumentWithLineEnd *>(pAccess);
-		}
-		return 0;
+	IDocument *MultiByteAccess() const {
+		return pAccess;
 	}
 	/** Safe version of operator[], returning a defined value for invalid position. */
 	char SafeGetCharAt(Sci_Position position, char chDefault=' ') {
@@ -120,17 +117,7 @@
 		return pAccess->LineStart(line);
 	}
 	Sci_Position LineEnd(Sci_Position line) {
-		if (documentVersion >= dvLineEnd) {
-			return (static_cast<IDocumentWithLineEnd *>(pAccess))->LineEnd(line);
-		} else {
-			// Old interface means only '\r', '\n' and '\r\n' line ends.
-			Sci_Position startNext = pAccess->LineStart(line+1);
-			const char chLineEnd = SafeGetCharAt(startNext-1);
-			if (chLineEnd == '\n' && (SafeGetCharAt(startNext-2)  == '\r'))
-				return startNext - 2;
-			else
-				return startNext - 1;
-		}
+		return pAccess->LineEnd(line);
 	}
 	int LevelAt(Sci_Position line) const {
 		return pAccess->GetLevel(line);
@@ -153,7 +140,7 @@
 	}
 	// Style setting
 	void StartAt(Sci_PositionU start) {
-		pAccess->StartStyling(start, '\377');
+		pAccess->StartStyling(start);
 		startPosStyling = start;
 	}
 	Sci_PositionU GetStartSegment() const {
@@ -197,6 +184,13 @@
 	}
 };
 
+struct LexicalClass {
+	int value;
+	const char *name;
+	const char *tags;
+	const char *description;
+};
+
 #ifdef SCI_NAMESPACE
 }
 #endif
diff -r 8d56eaef4f0a lexlib/LexerBase.cxx
--- a/lexlib/LexerBase.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexlib/LexerBase.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -18,13 +18,117 @@
 #include "LexAccessor.h"
 #include "Accessor.h"
 #include "LexerModule.h"
+#include "DefaultLexer.h"
 #include "LexerBase.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
 #endif
 
-LexerBase::LexerBase() {
+const char styleSubable[] = { 0 };
+
+DefaultLexer::DefaultLexer(const LexicalClass *lexClasses_, size_t nClasses_) :
+	lexClasses(lexClasses_) , nClasses(nClasses_) {
+}
+
+DefaultLexer::~DefaultLexer() {
+}
+
+void SCI_METHOD DefaultLexer::Release() {
+	delete this;
+}
+
+int SCI_METHOD DefaultLexer::Version() const {
+	return lvRelease4;
+}
+
+const char * SCI_METHOD DefaultLexer::PropertyNames() {
+	return "";
+}
+
+int SCI_METHOD DefaultLexer::PropertyType(const char *) {
+	return SC_TYPE_BOOLEAN;
+}
+
+const char * SCI_METHOD DefaultLexer::DescribeProperty(const char *) {
+	return "";
+}
+
+Sci_Position SCI_METHOD DefaultLexer::PropertySet(const char *, const char *) {
+	return -1;
+}
+
+const char * SCI_METHOD DefaultLexer::DescribeWordListSets() {
+	return "";
+}
+
+Sci_Position SCI_METHOD DefaultLexer::WordListSet(int, const char *) {
+	return -1;
+}
+
+void SCI_METHOD DefaultLexer::Fold(Sci_PositionU, Sci_Position, int, IDocument *) {
+}
+
+void * SCI_METHOD DefaultLexer::PrivateCall(int, void *) {
+	return nullptr;
+}
+
+int SCI_METHOD DefaultLexer::LineEndTypesSupported() {
+	return SC_LINE_END_TYPE_DEFAULT;
+}
+
+int SCI_METHOD DefaultLexer::AllocateSubStyles(int, int) {
+	return -1;
+}
+
+int SCI_METHOD DefaultLexer::SubStylesStart(int) {
+	return -1;
+}
+
+int SCI_METHOD DefaultLexer::SubStylesLength(int) {
+	return 0;
+}
+
+int SCI_METHOD DefaultLexer::StyleFromSubStyle(int subStyle) {
+	return subStyle;
+}
+
+int SCI_METHOD DefaultLexer::PrimaryStyleFromStyle(int style) {
+	return style;
+}
+
+void SCI_METHOD DefaultLexer::FreeSubStyles() {
+}
+
+void SCI_METHOD DefaultLexer::SetIdentifiers(int, const char *) {
+}
+
+int SCI_METHOD DefaultLexer::DistanceToSecondaryStyles() {
+	return 0;
+}
+
+const char * SCI_METHOD DefaultLexer::GetSubStyleBases() {
+	return styleSubable;
+}
+
+int SCI_METHOD DefaultLexer::MaximumNamedStyle() {
+	return nClasses;
+}
+
+const char * SCI_METHOD DefaultLexer::NameOfStyle(int style) {
+	return (style < MaximumNamedStyle()) ? lexClasses[style].name : "";
+}
+
+const char * SCI_METHOD DefaultLexer::TagsOfStyle(int style) {
+	return (style < MaximumNamedStyle()) ? lexClasses[style].tags : "";
+}
+
+const char * SCI_METHOD DefaultLexer::DescriptionOfStyle(int style) {
+	return (style < MaximumNamedStyle()) ? lexClasses[style].description : "";
+}
+
+LexerBase::LexerBase(const LexicalClass *lexClasses_, size_t nClasses_) :
+	lexClasses(lexClasses_), nClasses(nClasses_) {
 	for (int wl = 0; wl < numWordLists; wl++)
 		keyWordLists[wl] = new WordList;
 	keyWordLists[numWordLists] = 0;
@@ -43,7 +147,7 @@
 }
 
 int SCI_METHOD LexerBase::Version() const {
-	return lvOriginal;
+	return lvRelease4;
 }
 
 const char * SCI_METHOD LexerBase::PropertyNames() {
@@ -85,5 +189,59 @@
 }
 
 void * SCI_METHOD LexerBase::PrivateCall(int, void *) {
+	return nullptr;
+}
+
+int SCI_METHOD LexerBase::LineEndTypesSupported() {
+	return SC_LINE_END_TYPE_DEFAULT;
+}
+
+int SCI_METHOD LexerBase::AllocateSubStyles(int, int) {
+	return -1;
+}
+
+int SCI_METHOD LexerBase::SubStylesStart(int) {
+	return -1;
+}
+
+int SCI_METHOD LexerBase::SubStylesLength(int) {
 	return 0;
 }
+
+int SCI_METHOD LexerBase::StyleFromSubStyle(int subStyle) {
+	return subStyle;
+}
+
+int SCI_METHOD LexerBase::PrimaryStyleFromStyle(int style) {
+	return style;
+}
+
+void SCI_METHOD LexerBase::FreeSubStyles() {
+}
+
+void SCI_METHOD LexerBase::SetIdentifiers(int, const char *) {
+}
+
+int SCI_METHOD LexerBase::DistanceToSecondaryStyles() {
+	return 0;
+}
+
+const char * SCI_METHOD LexerBase::GetSubStyleBases() {
+	return styleSubable;
+}
+
+int SCI_METHOD LexerBase::MaximumNamedStyle() {
+	return nClasses;
+}
+
+const char * SCI_METHOD LexerBase::NameOfStyle(int style) {
+	return (style < MaximumNamedStyle()) ? lexClasses[style].name : "";
+}
+
+const char * SCI_METHOD LexerBase::TagsOfStyle(int style) {
+	return (style < MaximumNamedStyle()) ? lexClasses[style].tags : "";
+}
+
+const char * SCI_METHOD LexerBase::DescriptionOfStyle(int style) {
+	return (style < MaximumNamedStyle()) ? lexClasses[style].description : "";
+}
diff -r 8d56eaef4f0a lexlib/LexerBase.h
--- a/lexlib/LexerBase.h	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexlib/LexerBase.h	Mon Jun 19 20:21:57 2017 +1000
@@ -15,23 +15,39 @@
 // A simple lexer with no state
 class LexerBase : public ILexer {
 protected:
+	const LexicalClass *lexClasses;
+	size_t nClasses;
 	PropSetSimple props;
 	enum {numWordLists=KEYWORDSET_MAX+1};
 	WordList *keyWordLists[numWordLists+1];
 public:
-	LexerBase();
+	LexerBase(const LexicalClass *lexClasses_=nullptr, size_t nClasses_=0);
 	virtual ~LexerBase();
-	void SCI_METHOD Release();
-	int SCI_METHOD Version() const;
-	const char * SCI_METHOD PropertyNames();
-	int SCI_METHOD PropertyType(const char *name);
-	const char * SCI_METHOD DescribeProperty(const char *name);
-	Sci_Position SCI_METHOD PropertySet(const char *key, const char *val);
-	const char * SCI_METHOD DescribeWordListSets();
-	Sci_Position SCI_METHOD WordListSet(int n, const char *wl);
+	void SCI_METHOD Release() override;
+	int SCI_METHOD Version() const override;
+	const char * SCI_METHOD PropertyNames() override;
+	int SCI_METHOD PropertyType(const char *name) override;
+	const char * SCI_METHOD DescribeProperty(const char *name) override;
+	Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
+	const char * SCI_METHOD DescribeWordListSets() override;
+	Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
 	void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) = 0;
 	void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) = 0;
 	void * SCI_METHOD PrivateCall(int operation, void *pointer);
+	int SCI_METHOD LineEndTypesSupported() override;
+	int SCI_METHOD AllocateSubStyles(int styleBase, int numberStyles)  override;
+	int SCI_METHOD SubStylesStart(int styleBase) override;
+	int SCI_METHOD SubStylesLength(int styleBase) override;
+	int SCI_METHOD StyleFromSubStyle(int subStyle) override;
+	int SCI_METHOD PrimaryStyleFromStyle(int style) override;
+	void SCI_METHOD FreeSubStyles() override;
+	void SCI_METHOD SetIdentifiers(int style, const char *identifiers) override;
+	int SCI_METHOD DistanceToSecondaryStyles() override;
+	const char * SCI_METHOD GetSubStyleBases() override;
+	int SCI_METHOD MaximumNamedStyle() override;
+	const char * SCI_METHOD NameOfStyle(int style) override;
+	const char * SCI_METHOD TagsOfStyle(int style) override;
+	const char * SCI_METHOD DescriptionOfStyle(int style) override;
 };
 
 #ifdef SCI_NAMESPACE
diff -r 8d56eaef4f0a lexlib/LexerModule.cxx
--- a/lexlib/LexerModule.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexlib/LexerModule.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -19,6 +19,7 @@
 #include "LexAccessor.h"
 #include "Accessor.h"
 #include "LexerModule.h"
+#include "DefaultLexer.h"
 #include "LexerBase.h"
 #include "LexerSimple.h"
 
@@ -30,12 +31,16 @@
 	LexerFunction fnLexer_,
 	const char *languageName_,
 	LexerFunction fnFolder_,
-        const char *const wordListDescriptions_[]) :
+    const char *const wordListDescriptions_[],
+	const LexicalClass *lexClasses_,
+	size_t nClasses_) :
 	language(language_),
 	fnLexer(fnLexer_),
 	fnFolder(fnFolder_),
 	fnFactory(0),
 	wordListDescriptions(wordListDescriptions_),
+	lexClasses(lexClasses_),
+	nClasses(nClasses_),
 	languageName(languageName_) {
 }
 
@@ -48,6 +53,8 @@
 	fnFolder(0),
 	fnFactory(fnFactory_),
 	wordListDescriptions(wordListDescriptions_),
+	lexClasses(nullptr),
+	nClasses(0),
 	languageName(languageName_) {
 }
 
@@ -74,6 +81,14 @@
 	}
 }
 
+const LexicalClass *LexerModule::LexClasses() const {
+	return lexClasses;
+}
+
+size_t LexerModule::MaximumNamedStyle() const {
+	return nClasses;
+}
+
 ILexer *LexerModule::Create() const {
 	if (fnFactory)
 		return fnFactory();
diff -r 8d56eaef4f0a lexlib/LexerModule.h
--- a/lexlib/LexerModule.h	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexlib/LexerModule.h	Mon Jun 19 20:21:57 2017 +1000
@@ -14,6 +14,7 @@
 
 class Accessor;
 class WordList;
+struct LexicalClass;
 
 typedef void (*LexerFunction)(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle,
                   WordList *keywordlists[], Accessor &styler);
@@ -31,6 +32,8 @@
 	LexerFunction fnFolder;
 	LexerFactoryFunction fnFactory;
 	const char * const * wordListDescriptions;
+	const LexicalClass *lexClasses;
+	size_t nClasses;
 
 public:
 	const char *languageName;
@@ -38,7 +41,9 @@
 		LexerFunction fnLexer_,
 		const char *languageName_=0,
 		LexerFunction fnFolder_=0,
-		const char * const wordListDescriptions_[] = NULL);
+		const char * const wordListDescriptions_[] = NULL,
+		const LexicalClass *lexClasses_=nullptr,
+		size_t nClasses_=0);
 	LexerModule(int language_,
 		LexerFactoryFunction fnFactory_,
 		const char *languageName_,
@@ -50,6 +55,8 @@
 	// -1 is returned if no WordList information is available
 	int GetNumWordLists() const;
 	const char *GetWordListDescription(int index) const;
+	const LexicalClass *LexClasses() const;
+	size_t MaximumNamedStyle() const;
 
 	ILexer *Create() const;
 
diff -r 8d56eaef4f0a lexlib/LexerNoExceptions.cxx
--- a/lexlib/LexerNoExceptions.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexlib/LexerNoExceptions.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -17,6 +17,7 @@
 #include "LexAccessor.h"
 #include "Accessor.h"
 #include "LexerModule.h"
+#include "DefaultLexer.h"
 #include "LexerBase.h"
 #include "LexerNoExceptions.h"
 
diff -r 8d56eaef4f0a lexlib/LexerSimple.cxx
--- a/lexlib/LexerSimple.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexlib/LexerSimple.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -19,6 +19,7 @@
 #include "LexAccessor.h"
 #include "Accessor.h"
 #include "LexerModule.h"
+#include "DefaultLexer.h"
 #include "LexerBase.h"
 #include "LexerSimple.h"
 
@@ -26,7 +27,9 @@
 using namespace Scintilla;
 #endif
 
-LexerSimple::LexerSimple(const LexerModule *module_) : module(module_) {
+LexerSimple::LexerSimple(const LexerModule *module_) :
+	LexerBase(module_->LexClasses(), module_->MaximumNamedStyle()),
+	module(module_) {
 	for (int wl = 0; wl < module->GetNumWordLists(); wl++) {
 		if (!wordLists.empty())
 			wordLists += "\n";
diff -r 8d56eaef4f0a lexlib/StyleContext.h
--- a/lexlib/StyleContext.h	Mon Jun 19 12:10:18 2017 +1000
+++ b/lexlib/StyleContext.h	Mon Jun 19 20:21:57 2017 +1000
@@ -18,7 +18,7 @@
 // syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80
 class StyleContext {
 	LexAccessor &styler;
-	IDocumentWithLineEnd *multiByteAccess;
+	IDocument *multiByteAccess;
 	Sci_PositionU endPos;
 	Sci_PositionU lengthDocument;
 
diff -r 8d56eaef4f0a src/Document.cxx
--- a/src/Document.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/src/Document.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -85,11 +85,7 @@
 
 int LexInterface::LineEndTypesSupported() {
 	if (instance) {
-		const int interfaceVersion = instance->Version();
-		if (interfaceVersion >= lvSubStyles) {
-			ILexerWithSubStyles *ssinstance = static_cast<ILexerWithSubStyles *>(instance);
-			return ssinstance->LineEndTypesSupported();
-		}
+		return instance->LineEndTypesSupported();
 	}
 	return 0;
 }
@@ -2030,7 +2026,7 @@
     return charClass.GetCharsOfClass(characterClass, buffer);
 }
 
-void SCI_METHOD Document::StartStyling(Sci_Position position, char) {
+void SCI_METHOD Document::StartStyling(Sci_Position position) {
 	endStyled = position;
 }
 
diff -r 8d56eaef4f0a src/Document.h
--- a/src/Document.h	Mon Jun 19 12:10:18 2017 +1000
+++ b/src/Document.h	Mon Jun 19 20:21:57 2017 +1000
@@ -195,7 +195,7 @@
 
 /**
  */
-class Document : PerLine, public IDocumentWithLineEnd, public ILoader {
+class Document : PerLine, public IDocument, public ILoader {
 
 public:
 	/** Used to pair watcher pointer with user data. */
@@ -286,7 +286,7 @@
 	virtual void RemoveLine(Sci::Line line);
 
 	int SCI_METHOD Version() const {
-		return dvLineEnd;
+		return dvRelease4;
 	}
 
 	void SCI_METHOD SetErrorStatus(int status);
@@ -412,7 +412,7 @@
 	void SetDefaultCharClasses(bool includeWordClass);
 	void SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass);
 	int GetCharsOfClass(CharClassify::cc characterClass, unsigned char *buffer) const;
-	void SCI_METHOD StartStyling(Sci_Position position, char mask);
+	void SCI_METHOD StartStyling(Sci_Position position);
 	bool SCI_METHOD SetStyleFor(Sci_Position length, char style);
 	bool SCI_METHOD SetStyles(Sci_Position length, const char *styles);
 	Sci::Position GetEndStyled() const { return endStyled; }
diff -r 8d56eaef4f0a src/Editor.cxx
--- a/src/Editor.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/src/Editor.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -2091,7 +2091,7 @@
 
 void Editor::ClearDocumentStyle() {
 	pdoc->decorations.DeleteLexerDecorations();
-	pdoc->StartStyling(0, '\377');
+	pdoc->StartStyling(0);
 	pdoc->SetStyleFor(pdoc->Length(), 0);
 	cs.ShowAll();
 	SetAnnotationHeights(0, pdoc->LinesTotal());
@@ -5516,7 +5516,7 @@
 	for (i = 0; i < textLength; i++) {
 		text[i] = buffer[i*2+1];
 	}
-	pdoc->StartStyling(CurrentPosition(), static_cast<unsigned char>(0xff));
+	pdoc->StartStyling(CurrentPosition());
 	pdoc->SetStyles(textLength, text.c_str());
 	SetEmptySelection(sel.MainCaret() + lengthInserted);
 }
@@ -6353,7 +6353,7 @@
 		return pdoc->GetLineEndTypesActive();
 
 	case SCI_STARTSTYLING:
-		pdoc->StartStyling(static_cast<int>(wParam), static_cast<char>(lParam));
+		pdoc->StartStyling(static_cast<int>(wParam));
 		break;
 
 	case SCI_SETSTYLING:
diff -r 8d56eaef4f0a src/ScintillaBase.cxx
--- a/src/ScintillaBase.cxx	Mon Jun 19 12:10:18 2017 +1000
+++ b/src/ScintillaBase.cxx	Mon Jun 19 20:21:57 2017 +1000
@@ -582,6 +582,10 @@
 	void SetIdentifiers(int style, const char *identifiers);
 	int DistanceToSecondaryStyles();
 	const char *GetSubStyleBases();
+	int MaximumNamedStyle();
+	const char *NameOfStyle(int style);
+	const char *TagsOfStyle(int style);
+	const char *DescriptionOfStyle(int style);
 };
 
 #ifdef SCI_NAMESPACE
@@ -591,7 +595,7 @@
 LexState::LexState(Document *pdoc_) : LexInterface(pdoc_) {
 	lexCurrent = 0;
 	performingStyle = false;
-	interfaceVersion = lvOriginal;
+	interfaceVersion = lvRelease4;
 	lexLanguage = SCLEX_CONTAINER;
 }
 
@@ -615,7 +619,7 @@
 			instance->Release();
 			instance = 0;
 		}
-		interfaceVersion = lvOriginal;
+		interfaceVersion = lvRelease4;
 		lexCurrent = lex;
 		if (lexCurrent) {
 			instance = lexCurrent->Create();
@@ -722,74 +726,106 @@
 }
 
 int LexState::LineEndTypesSupported() {
-	if (instance && (interfaceVersion >= lvSubStyles)) {
-		return static_cast<ILexerWithSubStyles *>(instance)->LineEndTypesSupported();
+	if (instance) {
+		return instance->LineEndTypesSupported();
 	}
 	return 0;
 }
 
 int LexState::AllocateSubStyles(int styleBase, int numberStyles) {
-	if (instance && (interfaceVersion >= lvSubStyles)) {
-		return static_cast<ILexerWithSubStyles *>(instance)->AllocateSubStyles(styleBase, numberStyles);
+	if (instance) {
+		return instance->AllocateSubStyles(styleBase, numberStyles);
 	}
 	return -1;
 }
 
 int LexState::SubStylesStart(int styleBase) {
-	if (instance && (interfaceVersion >= lvSubStyles)) {
-		return static_cast<ILexerWithSubStyles *>(instance)->SubStylesStart(styleBase);
+	if (instance) {
+		return instance->SubStylesStart(styleBase);
 	}
 	return -1;
 }
 
 int LexState::SubStylesLength(int styleBase) {
-	if (instance && (interfaceVersion >= lvSubStyles)) {
-		return static_cast<ILexerWithSubStyles *>(instance)->SubStylesLength(styleBase);
+	if (instance) {
+		return instance->SubStylesLength(styleBase);
 	}
 	return 0;
 }
 
 int LexState::StyleFromSubStyle(int subStyle) {
-	if (instance && (interfaceVersion >= lvSubStyles)) {
-		return static_cast<ILexerWithSubStyles *>(instance)->StyleFromSubStyle(subStyle);
+	if (instance) {
+		return instance->StyleFromSubStyle(subStyle);
 	}
 	return 0;
 }
 
 int LexState::PrimaryStyleFromStyle(int style) {
-	if (instance && (interfaceVersion >= lvSubStyles)) {
-		return static_cast<ILexerWithSubStyles *>(instance)->PrimaryStyleFromStyle(style);
+	if (instance) {
+		return instance->PrimaryStyleFromStyle(style);
 	}
 	return 0;
 }
 
 void LexState::FreeSubStyles() {
-	if (instance && (interfaceVersion >= lvSubStyles)) {
-		static_cast<ILexerWithSubStyles *>(instance)->FreeSubStyles();
+	if (instance) {
+		instance->FreeSubStyles();
 	}
 }
 
 void LexState::SetIdentifiers(int style, const char *identifiers) {
-	if (instance && (interfaceVersion >= lvSubStyles)) {
-		static_cast<ILexerWithSubStyles *>(instance)->SetIdentifiers(style, identifiers);
+	if (instance) {
+		instance->SetIdentifiers(style, identifiers);
 		pdoc->ModifiedAt(0);
 	}
 }
 
 int LexState::DistanceToSecondaryStyles() {
-	if (instance && (interfaceVersion >= lvSubStyles)) {
-		return static_cast<ILexerWithSubStyles *>(instance)->DistanceToSecondaryStyles();
+	if (instance) {
+		return instance->DistanceToSecondaryStyles();
 	}
 	return 0;
 }
 
 const char *LexState::GetSubStyleBases() {
-	if (instance && (interfaceVersion >= lvSubStyles)) {
-		return static_cast<ILexerWithSubStyles *>(instance)->GetSubStyleBases();
+	if (instance) {
+		return instance->GetSubStyleBases();
 	}
 	return "";
 }
 
+int LexState::MaximumNamedStyle() {
+	if (instance) {
+		return instance->MaximumNamedStyle();
+	} else {
+		return -1;
+	}
+}
+
+const char *LexState::NameOfStyle(int style) {
+	if (instance) {
+		return instance->NameOfStyle(style);
+	} else {
+		return 0;
+	}
+}
+
+const char *LexState::TagsOfStyle(int style) {
+	if (instance) {
+		return instance->TagsOfStyle(style);
+	} else {
+		return 0;
+	}
+}
+
+const char *LexState::DescriptionOfStyle(int style) {
+	if (instance) {
+		return instance->DescriptionOfStyle(style);
+	} else {
+		return 0;
+	}
+}
+
 #endif
 
 void ScintillaBase::NotifyStyleToNeeded(Sci::Position endStyleNeeded) {
@@ -1101,6 +1137,19 @@
 
 	case SCI_GETSUBSTYLEBASES:
 		return StringResult(lParam, DocumentLexState()->GetSubStyleBases());
+
+	case SCI_GETMAXIMUMNAMEDSTYLE:
+		return DocumentLexState()->MaximumNamedStyle();
+
+	case SCI_NAMEOFSTYLE:
+		return StringResult(lParam, DocumentLexState()->NameOfStyle(wParam));
+
+	case SCI_TAGSOFSTYLE:
+		return StringResult(lParam, DocumentLexState()->TagsOfStyle(wParam));
+
+	case SCI_DESCRIPTIONOFSTYLE:
+		return StringResult(lParam, DocumentLexState()->DescriptionOfStyle(wParam));
+
 #endif
 
 	default:
