diff options
| -rw-r--r-- | cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj | 4 | ||||
| -rw-r--r-- | doc/ScintillaHistory.html | 4 | ||||
| -rw-r--r-- | gtk/deps.mak | 8 | ||||
| -rw-r--r-- | include/SciLexer.h | 10 | ||||
| -rw-r--r-- | include/Scintilla.iface | 12 | ||||
| -rw-r--r-- | lexers/LexX12.cxx | 341 | ||||
| -rw-r--r-- | src/Catalogue.cxx | 1 | ||||
| -rw-r--r-- | win32/deps.mak | 8 | ||||
| -rw-r--r-- | win32/nmdeps.mak | 8 | ||||
| -rw-r--r-- | win32/scintilla.mak | 1 | 
10 files changed, 397 insertions, 0 deletions
| diff --git a/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj b/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj index 74a6937a8..9e8af0da3 100644 --- a/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj +++ b/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj @@ -232,6 +232,7 @@  		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 */; }; +		AE894E1CB7328CAE5B2EF47E /* LexX12.cxx in Sources */ = {isa = PBXBuildFile; fileRef = ADA64364A443F3E3F02D294E /* LexX12.cxx */; };  /* End PBXBuildFile section */  /* Begin PBXFileReference section */ @@ -467,6 +468,7 @@  		8DC2EF5B0486A6940098B216 /* Scintilla.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Scintilla.framework; sourceTree = BUILT_PRODUCTS_DIR; };  		A95147A1AB7CADB00DAFE724 /* LexSAS.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexSAS.cxx; path = ../../lexers/LexSAS.cxx; sourceTree = SOURCE_ROOT; };  		D2F7E79907B2D74100F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; }; +		ADA64364A443F3E3F02D294E /* LexX12.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexX12.cxx; path = ../../lexers/LexX12.cxx; sourceTree = SOURCE_ROOT; };  /* End PBXFileReference section */  /* Begin PBXFrameworksBuildPhase section */ @@ -673,6 +675,7 @@  				114B6F0A11FA7526004FB6AB /* LexVerilog.cxx */,  				114B6F0B11FA7526004FB6AB /* LexVHDL.cxx */,  				11594BE8155B91DF0099E1FA /* LexVisualProlog.cxx */, +				ADA64364A443F3E3F02D294E /* LexX12.cxx */,  				114B6F0C11FA7526004FB6AB /* LexYAML.cxx */,  			);  			name = Lexers; @@ -1130,6 +1133,7 @@  				5F804AA6B60FE695863A39FE /* LexStata.cxx in Sources */,  				0ED84236A703D57578EBFD2F /* LexNim.cxx in Sources */,  				00724A59981D34F11A3D162F /* LexCIL.cxx in Sources */, +				AE894E1CB7328CAE5B2EF47E /* LexX12.cxx in Sources */,  			);  			runOnlyForDeploymentPostprocessing = 0;  		}; diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index be0b93292..cdd31553e 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -563,6 +563,10 @@  	<li>  	For Visual C++ 2019, /std:c++latest now includes some C++20 features so switch to /std:c++17.  	</li> + 	<li> +	Lexer added for X12. +	<a href="https://sourceforge.net/p/scintilla/feature-requests/1280/">Feature #1280</a>. +	</li>  	<li>  	Fix bug where changing identifier sets in lexers preserved previous identifiers.  	</li> diff --git a/gtk/deps.mak b/gtk/deps.mak index 98189e518..104746cf6 100644 --- a/gtk/deps.mak +++ b/gtk/deps.mak @@ -1921,6 +1921,14 @@ LexVisualProlog.o: \  	../lexlib/LexerModule.h \  	../lexlib/OptionSet.h \  	../lexlib/DefaultLexer.h +LexX12.o: \ +	../lexers/LexX12.cxx \ +	../include/ILexer.h \ +	../include/Sci_Position.h \ +	../include/Scintilla.h \ +	../include/SciLexer.h \ +	../lexlib/LexerModule.h \ +	../lexlib/DefaultLexer.h  LexYAML.o: \  	../lexers/LexYAML.cxx \  	../include/ILexer.h \ diff --git a/include/SciLexer.h b/include/SciLexer.h index 0230f8a2f..2d2de4d03 100644 --- a/include/SciLexer.h +++ b/include/SciLexer.h @@ -140,6 +140,7 @@  #define SCLEX_SAS 125  #define SCLEX_NIM 126  #define SCLEX_CIL 127 +#define SCLEX_X12 128  #define SCLEX_AUTOMATIC 1000  #define SCE_P_DEFAULT 0  #define SCE_P_COMMENTLINE 1 @@ -1885,6 +1886,15 @@  #define SCE_CIL_OPERATOR 8  #define SCE_CIL_IDENTIFIER 9  #define SCE_CIL_STRINGEOL 10 +#define SCE_X12_DEFAULT 0 +#define SCE_X12_BAD 1 +#define SCE_X12_ENVELOPE 2 +#define SCE_X12_FUNCTIONGROUP 3 +#define SCE_X12_TRANSACTIONSET 4 +#define SCE_X12_SEGMENTHEADER 5 +#define SCE_X12_SEGMENTEND 6 +#define SCE_X12_SEP_ELEMENT 7 +#define SCE_X12_SEP_SUBELEMENT 8  /* --Autogenerated -- end of section automatically generated from Scintilla.iface */  #endif diff --git a/include/Scintilla.iface b/include/Scintilla.iface index b19ebd0b3..d2b6f290c 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -2969,6 +2969,7 @@ val SCLEX_STATA=124  val SCLEX_SAS=125  val SCLEX_NIM=126  val SCLEX_CIL=127 +val SCLEX_X12=128  # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a  # value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -4954,6 +4955,17 @@ val SCE_CIL_LABEL=7  val SCE_CIL_OPERATOR=8  val SCE_CIL_IDENTIFIER=9  val SCE_CIL_STRINGEOL=10 +# Lexical states for SCLEX_X12 +lex X12=SCLEX_X12 SCE_X12_ +val SCE_X12_DEFAULT=0 +val SCE_X12_BAD=1 +val SCE_X12_ENVELOPE=2 +val SCE_X12_FUNCTIONGROUP=3 +val SCE_X12_TRANSACTIONSET=4 +val SCE_X12_SEGMENTHEADER=5 +val SCE_X12_SEGMENTEND=6 +val SCE_X12_SEP_ELEMENT=7 +val SCE_X12_SEP_SUBELEMENT=8  # Events diff --git a/lexers/LexX12.cxx b/lexers/LexX12.cxx new file mode 100644 index 000000000..270cc495d --- /dev/null +++ b/lexers/LexX12.cxx @@ -0,0 +1,341 @@ +// Scintilla Lexer for X12 +// Written by Iain Clarke, IMCSoft & Inobiz AB. +// X12 official documentation is behind a paywall, but there's a description of the syntax here: +// http://www.rawlinsecconsulting.com/x12tutorial/x12syn.html +// This code is subject to the same license terms as the rest of the scintilla project: +// The License.txt file describes the conditions under which this software may be distributed. +// + +// Header order must match order in scripts/HeaderOrder.txt +#include <cstdlib> +#include <cassert> +#include <cstring> +#include <cctype> + +#include <vector> +#include <algorithm> + +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" +#include "LexerModule.h" +#include "DefaultLexer.h" + +using namespace Scintilla; + +class LexerX12 : public DefaultLexer +{ +public: +	LexerX12(); +	virtual ~LexerX12() {} // virtual destructor, as we inherit from ILexer + +	static ILexer4 *Factory() { +		return new LexerX12; +	} + +	int SCI_METHOD Version() const override +	{ +		return lvRelease4; +	} +	void SCI_METHOD Release() override +	{ +		delete this; +	} + +	const char * SCI_METHOD PropertyNames() override +	{ +		return "fold"; +	} +	int SCI_METHOD PropertyType(const char *) override +	{ +		return SC_TYPE_BOOLEAN; // Only one property! +	} +	const char * SCI_METHOD DescribeProperty(const char *name) override +	{ +		if (!strcmp(name, "fold")) +			return "Whether to apply folding to document or not"; +		return NULL; +	} + +	Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override +	{ +		if (!strcmp(key, "fold")) +		{ +			m_bFold = strcmp(val, "0") ? true : false; +			return 0; +		} +		return -1; +	} +	const char * SCI_METHOD DescribeWordListSets() override +	{ +		return NULL; +	} +	Sci_Position SCI_METHOD WordListSet(int, const char *) override +	{ +		return -1; +	} +	void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override; +	void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override; +	void * SCI_METHOD PrivateCall(int, void *) override +	{ +		return NULL; +	} + +protected: +	struct Terminator +	{ +		int Style = SCE_X12_BAD; +		Sci_PositionU pos = 0; +		Sci_PositionU length = 0; +		int FoldChange = 0; +	}; +	Terminator InitialiseFromISA(IDocument *pAccess); +	Sci_PositionU FindPreviousSegmentStart(IDocument *pAccess, Sci_Position startPos) const; +	Terminator DetectSegmentHeader(IDocument *pAccess, Sci_PositionU pos) const; +	Terminator FindNextTerminator(IDocument *pAccess, Sci_PositionU pos, bool bJustSegmentTerminator = false) const; + +	bool m_bFold; +	char m_chSubElement; +	char m_chElement; +	char m_chSegment[3]; // might be CRLF +}; + +LexerModule lmX12(SCLEX_X12, LexerX12::Factory, "x12"); + +/////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// + +LexerX12::LexerX12() +{ +	m_bFold = false; +	m_chSegment[0] = m_chSegment[1] = m_chSegment[2] = m_chElement = m_chSubElement = 0; +} + +void LexerX12::Lex(Sci_PositionU startPos, Sci_Position length, int, IDocument *pAccess) +{ +	Sci_PositionU posFinish = startPos + length; + +	Terminator T = InitialiseFromISA(pAccess); + +	if (T.Style == SCE_X12_BAD) +	{ +		if (T.pos < startPos) +			T.pos = startPos; // we may be colouring in batches. +		pAccess->StartStyling(startPos); +		pAccess->SetStyleFor(T.pos - startPos, SCE_X12_ENVELOPE); +		pAccess->SetStyleFor(posFinish - T.pos, SCE_X12_BAD); +		return; +	} + +	// Look backwards for a segment start or a document beginning +	Sci_PositionU posCurrent = FindPreviousSegmentStart (pAccess, startPos); + +	// Style buffer, so we're not issuing loads of notifications +	pAccess->StartStyling(posCurrent); + +	while (posCurrent < posFinish) +	{ +		// Look for first element marker, so we can denote segment +		T = DetectSegmentHeader(pAccess, posCurrent); +		if (T.Style == SCE_X12_BAD) +			break; + +		pAccess->SetStyleFor(T.pos - posCurrent, T.Style); +		pAccess->SetStyleFor(T.length, SCE_X12_SEP_ELEMENT); +		posCurrent = T.pos + T.length; + +		while (T.Style != SCE_X12_BAD && T.Style != SCE_X12_SEGMENTEND) // Break on bad or segment ending +		{ +			T = FindNextTerminator(pAccess, posCurrent); +			if (T.Style == SCE_X12_BAD) +				break; + +			int Style = T.Style; +			if (T.Style == SCE_X12_SEGMENTEND && m_chSegment[0] == '\r') // don't style cr/crlf +				Style = SCE_X12_DEFAULT; + +			pAccess->SetStyleFor(T.pos - posCurrent, SCE_X12_DEFAULT); +			pAccess->SetStyleFor(T.length, Style); +			posCurrent = T.pos + T.length; +		} +		if (T.Style == SCE_X12_BAD) +			break; +	} + +	pAccess->SetStyleFor(posFinish - posCurrent, SCE_X12_BAD); +} + +void LexerX12::Fold(Sci_PositionU startPos, Sci_Position length, int, IDocument *pAccess) +{ +	if (!m_bFold) +		return; + +	// Are we even foldable? +	if (m_chSegment[0] != '\r' && m_chSegment[0] != '\n') // check for cr,lf,cr+lf. +		return; + +	Sci_PositionU posFinish = startPos + length; + +	// Look backwards for a segment start or a document beginning +	startPos = FindPreviousSegmentStart(pAccess, startPos); +	Terminator T; + +	Sci_PositionU currLine = pAccess->LineFromPosition(startPos); +	int levelCurrentStyle = SC_FOLDLEVELBASE; +	if (currLine > 0) +		levelCurrentStyle = pAccess->GetLevel(currLine - 1); // bottom 12 bits are level +	int indentCurrent = levelCurrentStyle & (SC_FOLDLEVELBASE - 1); + +	while (startPos < posFinish) +	{ +		T = DetectSegmentHeader(pAccess, startPos); +		int indentNext = indentCurrent + T.FoldChange; +		if (indentNext < 0) +			indentNext = 0; + +		levelCurrentStyle = (T.FoldChange > 0) ? (SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG) : SC_FOLDLEVELBASE; + +		currLine = pAccess->LineFromPosition(startPos); +		pAccess->SetLevel(currLine, levelCurrentStyle | indentCurrent); + +		T = FindNextTerminator(pAccess, startPos, true); +		startPos = T.pos + T.length; +		indentCurrent = indentNext; +	} +} + +LexerX12::Terminator LexerX12::InitialiseFromISA(IDocument *pAccess) +{ +	Sci_Position length = pAccess->Length(); +	char c; +	if (length <= 106) +		return { SCE_X12_BAD, 0 }; + +	pAccess->GetCharRange(&m_chElement, 3, 1); +	pAccess->GetCharRange(&m_chSubElement, 104, 1); +	pAccess->GetCharRange(m_chSegment, 105, 1); +	if (m_chSegment[0] == '\r') // are we CRLF? +	{ +		pAccess->GetCharRange(&c, 106, 1); +		if (c == '\n') +			m_chSegment[1] = c; +	} + +	// Validate we have an element separator, and it's not silly! +	if (m_chElement == '\0' || m_chElement == '\n' || m_chElement == '\r') +		return { SCE_X12_BAD, 3 }; + +	// Validate we have an element separator, and it's not silly! +	if (m_chSubElement == '\0' || m_chSubElement == '\n' || m_chSubElement == '\r') +		return { SCE_X12_BAD, 103 }; + +	if (m_chElement == m_chSubElement) +		return { SCE_X12_BAD, 104 }; +	if (m_chElement == m_chSegment[0]) +		return { SCE_X12_BAD, 105 }; +	if (m_chSubElement == m_chSegment[0]) +		return { SCE_X12_BAD, 104 }; + +	// Check we have element markers at all the right places! ISA element has fixed entries. +	std::vector<Sci_PositionU> ElementMarkers = { 3, 6, 17, 20, 31, 34, 50, 53, 69, 76, 81, 83, 89, 99, 101, 103  }; +	for (auto i : ElementMarkers) +	{ +		pAccess->GetCharRange(&c, i, 1); +		if (c != m_chElement) +			return { SCE_X12_BAD, i }; +	} +	// Check we have no element markers anywhere else! +	for (Sci_PositionU i = 0; i < 105; i++) +	{ +		if (std::find(ElementMarkers.begin(), ElementMarkers.end(), i) != ElementMarkers.end()) +			continue; + +		pAccess->GetCharRange(&c, i, 1); +		if (c == m_chElement) +			return { SCE_X12_BAD, i }; +	} + +	return { SCE_X12_ENVELOPE }; +} + +Sci_PositionU LexerX12::FindPreviousSegmentStart(IDocument *pAccess, Sci_Position startPos) const +{ +	char c; + +	for ( ; startPos > 0; startPos--) +	{ +		pAccess->GetCharRange(&c, startPos, 1); +		if (c != m_chSegment[0]) +			continue; +		// we've matched one - if this is not crlf we're done. +		if (!m_chSegment[1]) +			return startPos + 1; +		pAccess->GetCharRange(&c, startPos+1, 1); +		if (c == m_chSegment[1]) +			return startPos + 2; +	} +	// We didn't find a ', so just go with the beginning +	return 0; +} + +LexerX12::Terminator LexerX12::DetectSegmentHeader(IDocument *pAccess, Sci_PositionU pos) const +{ +	Sci_PositionU posStart = pos; +	Sci_Position Length = pAccess->Length(); +	char Buf[6] = { 0 }; +	while (pos - posStart < 5 && pos < (Sci_PositionU)Length) +	{ +		pAccess->GetCharRange(Buf + pos - posStart, pos, 1); +		if (Buf [pos - posStart] != m_chElement) // more? +		{ +			pos++; +			continue; +		} +		if (strcmp(Buf, "ISA*") == 0) +			return { SCE_X12_ENVELOPE, pos, 1, +1 }; +		if (strcmp(Buf, "IEA*") == 0) +			return { SCE_X12_ENVELOPE, pos, 1, -1 }; +		if (strcmp(Buf, "GS*") == 0) +			return { SCE_X12_FUNCTIONGROUP, pos, 1, +1 }; +		if (strcmp(Buf, "GE*") == 0) +			return { SCE_X12_FUNCTIONGROUP, pos, 1, -1 }; +		if (strcmp(Buf, "ST*") == 0) +			return { SCE_X12_TRANSACTIONSET, pos, 1, +1 }; +		if (strcmp(Buf, "SE*") == 0) +			return { SCE_X12_TRANSACTIONSET, pos, 1, -1 }; +		return { SCE_X12_SEGMENTHEADER, pos, 1, 0 }; +	} +	return { SCE_X12_BAD, pos, 0, 0 }; +} + +LexerX12::Terminator LexerX12::FindNextTerminator(IDocument *pAccess, Sci_PositionU pos, bool bJustSegmentTerminator) const +{ +	char c; +	Sci_Position Length = pAccess->Length(); + +	while (pos < (Sci_PositionU)Length) +	{ +		pAccess->GetCharRange(&c, pos, 1); +		if (!bJustSegmentTerminator && c == m_chElement) +			return { SCE_X12_SEP_ELEMENT, pos, 1 }; +		else if (!bJustSegmentTerminator && c == m_chSubElement) +			return { SCE_X12_SEP_SUBELEMENT, pos, 1 }; +		else if (c == m_chSegment[0]) +		{ +			if (!m_chSegment[1]) +				return { SCE_X12_SEGMENTEND, pos, 1 }; +			pos++; +			if (pos >= (Sci_PositionU)Length) +				break; +			pAccess->GetCharRange(&c, pos, 1); +			if (c == m_chSegment[1]) +				return { SCE_X12_SEGMENTEND, pos-1, 2 }; +		} +		pos++; +	} + +	return { SCE_X12_BAD, pos }; +} diff --git a/src/Catalogue.cxx b/src/Catalogue.cxx index ab951435e..d221113ce 100644 --- a/src/Catalogue.cxx +++ b/src/Catalogue.cxx @@ -194,6 +194,7 @@ int Scintilla_LinkLexers() {  	LINK_LEXER(lmVerilog);  	LINK_LEXER(lmVHDL);  	LINK_LEXER(lmVisualProlog); +	LINK_LEXER(lmX12);  	LINK_LEXER(lmXML);  	LINK_LEXER(lmYAML); diff --git a/win32/deps.mak b/win32/deps.mak index 4bc99e211..8c53840ad 100644 --- a/win32/deps.mak +++ b/win32/deps.mak @@ -1963,6 +1963,14 @@ LexVisualProlog.o: \  	../lexlib/LexerModule.h \  	../lexlib/OptionSet.h \  	../lexlib/DefaultLexer.h +LexX12.o: \ +	../lexers/LexX12.cxx \ +	../include/ILexer.h \ +	../include/Sci_Position.h \ +	../include/Scintilla.h \ +	../include/SciLexer.h \ +	../lexlib/LexerModule.h \ +	../lexlib/DefaultLexer.h  LexYAML.o: \  	../lexers/LexYAML.cxx \  	../include/ILexer.h \ diff --git a/win32/nmdeps.mak b/win32/nmdeps.mak index 9cf46b03b..8ddedfc79 100644 --- a/win32/nmdeps.mak +++ b/win32/nmdeps.mak @@ -1963,6 +1963,14 @@ $(DIR_O)/LexVisualProlog.obj: \  	../lexlib/LexerModule.h \  	../lexlib/OptionSet.h \  	../lexlib/DefaultLexer.h +$(DIR_O)/LexX12.obj: \ +	../lexers/LexX12.cxx \ +	../include/ILexer.h \ +	../include/Sci_Position.h \ +	../include/Scintilla.h \ +	../include/SciLexer.h \ +	../lexlib/LexerModule.h \ +	../lexlib/DefaultLexer.h  $(DIR_O)/LexYAML.obj: \  	../lexers/LexYAML.cxx \  	../include/ILexer.h \ diff --git a/win32/scintilla.mak b/win32/scintilla.mak index 8c72176c6..9b91e7639 100644 --- a/win32/scintilla.mak +++ b/win32/scintilla.mak @@ -216,6 +216,7 @@ LEXOBJS=\  	$(DIR_O)\LexVerilog.obj \  	$(DIR_O)\LexVHDL.obj \  	$(DIR_O)\LexVisualProlog.obj \ +	$(DIR_O)\LexX12.obj \  	$(DIR_O)\LexYAML.obj \  #--Autogenerated -- end of automatically generated section | 
