mirror of
				https://github.com/notepad-plus-plus/notepad-plus-plus.git
				synced 2025-10-31 03:24:04 +01:00 
			
		
		
		
	Update with https://www.scintilla.org/scintilla521.zip https://www.scintilla.org/lexilla515.zip - fix setting to bring Scintilla::PositionCR from ScintillaStructures.h inline with Sci_Position.h Sci_PositionCR - add workaround to enable lexer for searchResult commented out SCI_SETILEXER call on searchResult to get one result which is correctly handled by the lexer, added comment about the current problem with property @MarkingsStruct which seems to disappear after call to SCI_SETILEXER or CreateLexer - corrected usage of ObjC lexer - removed unnecessary filter stuff - use own sections for scintilla and lexilla build targets and allow parallel builds - as libscilex is no longer existing, changed to libscintilla - adapt makefiles and cmake - use VS2019 - started simple changes for createlexer adaptations, nullpointercheck missing on return of lexer name from deprecated LexerNameFromID -> undefined behaviour - movement from id -> lexer name, mostly done via LexerNameFromID + switching off corresponding compiler warning - changed to SCI_SETILEXER from SCI_SETLEXER, SCI_SETLEXERLANGUAGE needs to be corrected, see Scintilla5Migration.html - just commented out: SCI_LOADLEXERLIBRARY Fix #10504, close #11419
		
			
				
	
	
		
			508 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			508 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Scintilla\ source code edit control
 | |
| /** @file LexTCMD.cxx
 | |
|  ** Lexer for Take Command / TCC batch scripts (.bat, .btm, .cmd).
 | |
|  **/
 | |
| // Written by Rex Conn (rconn [at] jpsoft [dot] com)
 | |
| // based on the CMD lexer
 | |
| // The License.txt file describes the conditions under which this software may be distributed.
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <stdio.h>
 | |
| #include <stdarg.h>
 | |
| #include <assert.h>
 | |
| #include <ctype.h>
 | |
| 
 | |
| #include <string>
 | |
| #include <string_view>
 | |
| 
 | |
| #include "ILexer.h"
 | |
| #include "Scintilla.h"
 | |
| #include "SciLexer.h"
 | |
| 
 | |
| #include "WordList.h"
 | |
| #include "LexAccessor.h"
 | |
| #include "Accessor.h"
 | |
| #include "StyleContext.h"
 | |
| #include "CharacterSet.h"
 | |
| #include "LexerModule.h"
 | |
| 
 | |
| using namespace Lexilla;
 | |
| 
 | |
| 
 | |
| static bool IsAlphabetic(int ch) {
 | |
| 	return IsASCII(ch) && isalpha(ch);
 | |
| }
 | |
| 
 | |
| static inline bool AtEOL(Accessor &styler, Sci_PositionU i) {
 | |
| 	return (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n'));
 | |
| }
 | |
| 
 | |
| // Tests for BATCH Operators
 | |
| static bool IsBOperator(char ch) {
 | |
| 	return (ch == '=') || (ch == '+') || (ch == '>') || (ch == '<') || (ch == '|') || (ch == '&') || (ch == '!') || (ch == '?') || (ch == '*') || (ch == '(') || (ch == ')');
 | |
| }
 | |
| 
 | |
| // Tests for BATCH Separators
 | |
| static bool IsBSeparator(char ch) {
 | |
| 	return (ch == '\\') || (ch == '.') || (ch == ';') || (ch == ' ') || (ch == '\t') || (ch == '[') || (ch == ']') || (ch == '\"') || (ch == '\'') || (ch == '/');
 | |
| }
 | |
| 
 | |
| // Find length of CMD FOR variable with modifier (%~...) or return 0
 | |
| static unsigned int GetBatchVarLen( char *wordBuffer )
 | |
| {
 | |
| 	int nLength = 0;
 | |
| 	if ( wordBuffer[0] == '%' ) {
 | |
| 
 | |
| 		if ( wordBuffer[1] == '~' )
 | |
| 			nLength = 2;
 | |
| 		else if (( wordBuffer[1] == '%' ) && ( wordBuffer[2] == '~' ))
 | |
| 			nLength++;
 | |
| 		else
 | |
| 			return 0;
 | |
| 
 | |
| 		for ( ; ( wordBuffer[nLength] ); nLength++ ) {
 | |
| 
 | |
| 			switch ( toupper(wordBuffer[nLength]) ) {
 | |
| 			case 'A':
 | |
| 				// file attributes
 | |
| 			case 'D':
 | |
| 				// drive letter only
 | |
| 			case 'F':
 | |
| 				// fully qualified path name
 | |
| 			case 'N':
 | |
| 				// filename only
 | |
| 			case 'P':
 | |
| 				// path only
 | |
| 			case 'S':
 | |
| 				// short name
 | |
| 			case 'T':
 | |
| 				// date / time of file
 | |
| 			case 'X':
 | |
| 				// file extension only
 | |
| 			case 'Z':
 | |
| 				// file size
 | |
| 				break;
 | |
| 			default:
 | |
| 				return nLength;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nLength;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void ColouriseTCMDLine( char *lineBuffer, Sci_PositionU lengthLine, Sci_PositionU startLine, Sci_PositionU endPos, WordList *keywordlists[], Accessor &styler)
 | |
| {
 | |
| 	Sci_PositionU offset = 0;	// Line Buffer Offset
 | |
| 	char wordBuffer[260];		// Word Buffer - large to catch long paths
 | |
| 	Sci_PositionU wbl;			// Word Buffer Length
 | |
| 	Sci_PositionU wbo;			// Word Buffer Offset - also Special Keyword Buffer Length
 | |
| 	WordList &keywords = *keywordlists[0];      // Internal Commands
 | |
| //	WordList &keywords2 = *keywordlists[1];     // Aliases (optional)
 | |
| 	bool isDelayedExpansion = 1;				// !var!
 | |
| 
 | |
| 	bool continueProcessing = true;	// Used to toggle Regular Keyword Checking
 | |
| 	// Special Keywords are those that allow certain characters without whitespace after the command
 | |
| 	// Examples are: cd. cd\ echo: echo. path=
 | |
| 	bool inString = false; // Used for processing while ""
 | |
| 	// Special Keyword Buffer used to determine if the first n characters is a Keyword
 | |
| 	char sKeywordBuffer[260] = "";	// Special Keyword Buffer
 | |
| 	bool sKeywordFound;		// Exit Special Keyword for-loop if found
 | |
| 
 | |
| 	// Skip leading whitespace
 | |
| 	while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {
 | |
| 		offset++;
 | |
| 	}
 | |
| 	// Colorize Default Text
 | |
| 	styler.ColourTo(startLine + offset - 1, SCE_TCMD_DEFAULT);
 | |
| 
 | |
| 	if ( offset >= lengthLine )
 | |
| 		return;
 | |
| 
 | |
| 	// Check for Fake Label (Comment) or Real Label - return if found
 | |
| 	if (lineBuffer[offset] == ':') {
 | |
| 		if (lineBuffer[offset + 1] == ':') {
 | |
| 			// Colorize Fake Label (Comment) - :: is the same as REM
 | |
| 			styler.ColourTo(endPos, SCE_TCMD_COMMENT);
 | |
| 		} else {
 | |
| 			// Colorize Real Label
 | |
| 			styler.ColourTo(endPos, SCE_TCMD_LABEL);
 | |
| 		}
 | |
| 		return;
 | |
| 
 | |
| 	// Check for Comment - return if found
 | |
| 	} else if (( CompareNCaseInsensitive(lineBuffer+offset, "rem", 3) == 0 ) && (( lineBuffer[offset+3] == 0 ) || ( isspace(lineBuffer[offset+3] )))) {
 | |
| 			styler.ColourTo(endPos, SCE_TCMD_COMMENT);
 | |
| 			return;
 | |
| 
 | |
| 	// Check for Drive Change (Drive Change is internal command) - return if found
 | |
| 	} else if ((IsAlphabetic(lineBuffer[offset])) &&
 | |
| 		(lineBuffer[offset + 1] == ':') &&
 | |
| 		((isspacechar(lineBuffer[offset + 2])) ||
 | |
| 		(((lineBuffer[offset + 2] == '\\')) &&
 | |
| 		(isspacechar(lineBuffer[offset + 3]))))) {
 | |
| 		// Colorize Regular Keyword
 | |
| 		styler.ColourTo(endPos, SCE_TCMD_WORD);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	// Check for Hide Command (@ECHO OFF/ON)
 | |
| 	if (lineBuffer[offset] == '@') {
 | |
| 		styler.ColourTo(startLine + offset, SCE_TCMD_HIDE);
 | |
| 		offset++;
 | |
| 	}
 | |
| 	// Skip whitespace
 | |
| 	while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {
 | |
| 		offset++;
 | |
| 	}
 | |
| 
 | |
| 	// Read remainder of line word-at-a-time or remainder-of-word-at-a-time
 | |
| 	while (offset < lengthLine) {
 | |
| 		if (offset > startLine) {
 | |
| 			// Colorize Default Text
 | |
| 			styler.ColourTo(startLine + offset - 1, SCE_TCMD_DEFAULT);
 | |
| 		}
 | |
| 		// Copy word from Line Buffer into Word Buffer
 | |
| 		wbl = 0;
 | |
| 		for (; offset < lengthLine && ( wbl < 260 ) && !isspacechar(lineBuffer[offset]); wbl++, offset++) {
 | |
| 			wordBuffer[wbl] = static_cast<char>(tolower(lineBuffer[offset]));
 | |
| 		}
 | |
| 		wordBuffer[wbl] = '\0';
 | |
| 		wbo = 0;
 | |
| 
 | |
| 		// Check for Separator
 | |
| 		if (IsBSeparator(wordBuffer[0])) {
 | |
| 
 | |
| 			// Reset Offset to re-process remainder of word
 | |
| 			offset -= (wbl - 1);
 | |
| 			// Colorize Default Text
 | |
| 			styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);
 | |
| 
 | |
| 			if (wordBuffer[0] == '"')
 | |
| 				inString = !inString;
 | |
| 
 | |
| 		// Check for Regular expression
 | |
| 		} else if (( wordBuffer[0] == ':' ) && ( wordBuffer[1] == ':' ) && (continueProcessing)) {
 | |
| 
 | |
| 			// Colorize Regular exoressuin
 | |
| 			styler.ColourTo(startLine + offset - 1, SCE_TCMD_DEFAULT);
 | |
| 			// No need to Reset Offset
 | |
| 
 | |
| 		// Check for Labels in text (... :label)
 | |
| 		} else if (wordBuffer[0] == ':' && isspacechar(lineBuffer[offset - wbl - 1])) {
 | |
| 			// Colorize Default Text
 | |
| 			styler.ColourTo(startLine + offset - 1 - wbl, SCE_TCMD_DEFAULT);
 | |
| 			// Colorize Label
 | |
| 			styler.ColourTo(startLine + offset - 1, SCE_TCMD_CLABEL);
 | |
| 			// No need to Reset Offset
 | |
| 		// Check for delayed expansion Variable (!x...!)
 | |
| 		} else if (isDelayedExpansion && wordBuffer[0] == '!') {
 | |
| 			// Colorize Default Text
 | |
| 			styler.ColourTo(startLine + offset - 1 - wbl, SCE_TCMD_DEFAULT);
 | |
| 			wbo++;
 | |
| 			// Search to end of word for second !
 | |
| 			while ((wbo < wbl) && (wordBuffer[wbo] != '!') && (!IsBOperator(wordBuffer[wbo])) && (!IsBSeparator(wordBuffer[wbo]))) {
 | |
| 				wbo++;
 | |
| 			}
 | |
| 			if (wordBuffer[wbo] == '!') {
 | |
| 				wbo++;
 | |
| 				// Colorize Environment Variable
 | |
| 				styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_TCMD_EXPANSION);
 | |
| 			} else {
 | |
| 				wbo = 1;
 | |
| 				// Colorize Symbol
 | |
| 				styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_TCMD_DEFAULT);
 | |
| 			}
 | |
| 
 | |
| 			// Reset Offset to re-process remainder of word
 | |
| 			offset -= (wbl - wbo);
 | |
| 
 | |
| 		// Check for Regular Keyword in list
 | |
| 		} else if ((keywords.InList(wordBuffer)) &&	(!inString) && (continueProcessing)) {
 | |
| 
 | |
| 			// ECHO, PATH, and PROMPT require no further Regular Keyword Checking
 | |
| 			if ((CompareCaseInsensitive(wordBuffer, "echo") == 0) ||
 | |
| 			  (CompareCaseInsensitive(sKeywordBuffer, "echos") == 0) ||
 | |
| 			  (CompareCaseInsensitive(sKeywordBuffer, "echoerr") == 0) ||
 | |
| 			  (CompareCaseInsensitive(sKeywordBuffer, "echoserr") == 0) ||
 | |
| 			  (CompareCaseInsensitive(wordBuffer, "path") == 0) ||
 | |
| 			  (CompareCaseInsensitive(wordBuffer, "prompt") == 0)) {
 | |
| 				continueProcessing = false;
 | |
| 			}
 | |
| 
 | |
| 			// Colorize Regular keyword
 | |
| 			styler.ColourTo(startLine + offset - 1, SCE_TCMD_WORD);
 | |
| 			// No need to Reset Offset
 | |
| 
 | |
| 		} else if ((wordBuffer[0] != '%') && (wordBuffer[0] != '!') && (!IsBOperator(wordBuffer[0])) &&	(!inString) && (continueProcessing)) {
 | |
| 
 | |
| 			// a few commands accept "illegal" syntax -- cd\, echo., etc.
 | |
| 			sscanf( wordBuffer, "%[^.<>|&=\\/]", sKeywordBuffer );
 | |
| 			sKeywordFound = false;
 | |
| 
 | |
| 			if ((CompareCaseInsensitive(sKeywordBuffer, "echo") == 0) ||
 | |
| 			  (CompareCaseInsensitive(sKeywordBuffer, "echos") == 0) ||
 | |
| 			  (CompareCaseInsensitive(sKeywordBuffer, "echoerr") == 0) ||
 | |
| 			  (CompareCaseInsensitive(sKeywordBuffer, "echoserr") == 0) ||
 | |
| 			  (CompareCaseInsensitive(sKeywordBuffer, "cd") == 0) ||
 | |
| 			  (CompareCaseInsensitive(sKeywordBuffer, "path") == 0) ||
 | |
| 			  (CompareCaseInsensitive(sKeywordBuffer, "prompt") == 0)) {
 | |
| 
 | |
| 				// no further Regular Keyword Checking
 | |
| 				continueProcessing = false;
 | |
| 				sKeywordFound = true;
 | |
| 				wbo = (Sci_PositionU)strlen( sKeywordBuffer );
 | |
| 
 | |
| 				// Colorize Special Keyword as Regular Keyword
 | |
| 				styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_TCMD_WORD);
 | |
| 				// Reset Offset to re-process remainder of word
 | |
| 				offset -= (wbl - wbo);
 | |
| 			}
 | |
| 
 | |
| 			// Check for Default Text
 | |
| 			if (!sKeywordFound) {
 | |
| 				wbo = 0;
 | |
| 				// Read up to %, Operator or Separator
 | |
| 				while ((wbo < wbl) && (wordBuffer[wbo] != '%') && (!isDelayedExpansion || wordBuffer[wbo] != '!') && (!IsBOperator(wordBuffer[wbo])) &&	(!IsBSeparator(wordBuffer[wbo]))) {
 | |
| 					wbo++;
 | |
| 				}
 | |
| 				// Colorize Default Text
 | |
| 				styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_TCMD_DEFAULT);
 | |
| 				// Reset Offset to re-process remainder of word
 | |
| 				offset -= (wbl - wbo);
 | |
| 			}
 | |
| 
 | |
| 		// Check for Argument  (%n), Environment Variable (%x...%) or Local Variable (%%a)
 | |
| 		} else if (wordBuffer[0] == '%') {
 | |
| 			unsigned int varlen;
 | |
| 			unsigned int n = 1;
 | |
| 			// Colorize Default Text
 | |
| 			styler.ColourTo(startLine + offset - 1 - wbl, SCE_TCMD_DEFAULT);
 | |
| 			wbo++;
 | |
| 
 | |
| 			// check for %[nn] syntax
 | |
| 			if ( wordBuffer[1] == '[' ) {
 | |
| 				n++;
 | |
| 				while ((n < wbl) && (wordBuffer[n] != ']')) {
 | |
| 					n++;
 | |
| 				}
 | |
| 				if ( wordBuffer[n] == ']' )
 | |
| 					n++;
 | |
| 				goto ColorizeArg;
 | |
| 			}
 | |
| 
 | |
| 			// Search to end of word for second % or to the first terminator (can be a long path)
 | |
| 			while ((wbo < wbl) && (wordBuffer[wbo] != '%') && (!IsBOperator(wordBuffer[wbo])) && (!IsBSeparator(wordBuffer[wbo]))) {
 | |
| 				wbo++;
 | |
| 			}
 | |
| 
 | |
| 			// Check for Argument (%n) or (%*)
 | |
| 			if (((isdigit(wordBuffer[1])) || (wordBuffer[1] == '*')) && (wordBuffer[wbo] != '%')) {
 | |
| 				while (( wordBuffer[n] ) && ( strchr( "%0123456789*#$", wordBuffer[n] ) != NULL ))
 | |
| 					n++;
 | |
| ColorizeArg:
 | |
| 				// Colorize Argument
 | |
| 				styler.ColourTo(startLine + offset - 1 - (wbl - n), SCE_TCMD_IDENTIFIER);
 | |
| 				// Reset Offset to re-process remainder of word
 | |
| 				offset -= (wbl - n);
 | |
| 
 | |
| 			// Check for Variable with modifiers (%~...)
 | |
| 			} else if ((varlen = GetBatchVarLen(wordBuffer)) != 0) {
 | |
| 
 | |
| 				// Colorize Variable
 | |
| 				styler.ColourTo(startLine + offset - 1 - (wbl - varlen), SCE_TCMD_IDENTIFIER);
 | |
| 				// Reset Offset to re-process remainder of word
 | |
| 				offset -= (wbl - varlen);
 | |
| 
 | |
| 			// Check for Environment Variable (%x...%)
 | |
| 			} else if (( wordBuffer[1] ) && ( wordBuffer[1] != '%')) {
 | |
| 				if ( wordBuffer[wbo] == '%' )
 | |
| 					wbo++;
 | |
| 
 | |
| 				// Colorize Environment Variable
 | |
| 				styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_TCMD_ENVIRONMENT);
 | |
| 				// Reset Offset to re-process remainder of word
 | |
| 				offset -= (wbl - wbo);
 | |
| 
 | |
| 			// Check for Local Variable (%%a)
 | |
| 			} else if (	(wbl > 2) && (wordBuffer[1] == '%') && (wordBuffer[2] != '%') && (!IsBOperator(wordBuffer[2])) && (!IsBSeparator(wordBuffer[2]))) {
 | |
| 
 | |
| 				n = 2;
 | |
| 				while (( wordBuffer[n] ) && (!IsBOperator(wordBuffer[n])) && (!IsBSeparator(wordBuffer[n])))
 | |
| 					n++;
 | |
| 
 | |
| 				// Colorize Local Variable
 | |
| 				styler.ColourTo(startLine + offset - 1 - (wbl - n), SCE_TCMD_IDENTIFIER);
 | |
| 				// Reset Offset to re-process remainder of word
 | |
| 				offset -= (wbl - n);
 | |
| 
 | |
| 			// Check for %%
 | |
| 			} else if ((wbl > 1) && (wordBuffer[1] == '%')) {
 | |
| 
 | |
| 				// Colorize Symbols
 | |
| 				styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_TCMD_DEFAULT);
 | |
| 				// Reset Offset to re-process remainder of word
 | |
| 				offset -= (wbl - 2);
 | |
| 			} else {
 | |
| 
 | |
| 				// Colorize Symbol
 | |
| 				styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_TCMD_DEFAULT);
 | |
| 				// Reset Offset to re-process remainder of word
 | |
| 				offset -= (wbl - 1);
 | |
| 			}
 | |
| 
 | |
| 		// Check for Operator
 | |
| 		} else if (IsBOperator(wordBuffer[0])) {
 | |
| 			// Colorize Default Text
 | |
| 			styler.ColourTo(startLine + offset - 1 - wbl, SCE_TCMD_DEFAULT);
 | |
| 
 | |
| 			// Check for Pipe, compound, or conditional Operator
 | |
| 			if ((wordBuffer[0] == '|') || (wordBuffer[0] == '&')) {
 | |
| 
 | |
| 				// Colorize Pipe Operator
 | |
| 				styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_TCMD_OPERATOR);
 | |
| 				// Reset Offset to re-process remainder of word
 | |
| 				offset -= (wbl - 1);
 | |
| 				continueProcessing = true;
 | |
| 
 | |
| 			// Check for Other Operator
 | |
| 			} else {
 | |
| 				// Check for > Operator
 | |
| 				if ((wordBuffer[0] == '>') || (wordBuffer[0] == '<')) {
 | |
| 					// Turn Keyword and External Command / Program checking back on
 | |
| 					continueProcessing = true;
 | |
| 				}
 | |
| 				// Colorize Other Operator
 | |
| 				if (!inString || !(wordBuffer[0] == '(' || wordBuffer[0] == ')'))
 | |
| 					styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_TCMD_OPERATOR);
 | |
| 				// Reset Offset to re-process remainder of word
 | |
| 				offset -= (wbl - 1);
 | |
| 			}
 | |
| 
 | |
| 		// Check for Default Text
 | |
| 		} else {
 | |
| 			// Read up to %, Operator or Separator
 | |
| 			while ((wbo < wbl) && (wordBuffer[wbo] != '%') && (!isDelayedExpansion || wordBuffer[wbo] != '!') && (!IsBOperator(wordBuffer[wbo])) &&	(!IsBSeparator(wordBuffer[wbo]))) {
 | |
| 				wbo++;
 | |
| 			}
 | |
| 			// Colorize Default Text
 | |
| 			styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_TCMD_DEFAULT);
 | |
| 			// Reset Offset to re-process remainder of word
 | |
| 			offset -= (wbl - wbo);
 | |
| 		}
 | |
| 
 | |
| 		// Skip whitespace - nothing happens if Offset was Reset
 | |
| 		while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {
 | |
| 			offset++;
 | |
| 		}
 | |
| 	}
 | |
| 	// Colorize Default Text for remainder of line - currently not lexed
 | |
| 	styler.ColourTo(endPos, SCE_TCMD_DEFAULT);
 | |
| }
 | |
| 
 | |
| static void ColouriseTCMDDoc( Sci_PositionU startPos, Sci_Position length, int /*initStyle*/, WordList *keywordlists[], Accessor &styler )
 | |
| {
 | |
| 	char lineBuffer[16384];
 | |
| 
 | |
| 	styler.StartAt(startPos);
 | |
| 	styler.StartSegment(startPos);
 | |
| 	Sci_PositionU linePos = 0;
 | |
| 	Sci_PositionU startLine = startPos;
 | |
| 	for (Sci_PositionU i = startPos; i < startPos + length; i++) {
 | |
| 		lineBuffer[linePos++] = styler[i];
 | |
| 		if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
 | |
| 			// End of line (or of line buffer) met, colourise it
 | |
| 			lineBuffer[linePos] = '\0';
 | |
| 			ColouriseTCMDLine(lineBuffer, linePos, startLine, i, keywordlists, styler);
 | |
| 			linePos = 0;
 | |
| 			startLine = i + 1;
 | |
| 		}
 | |
| 	}
 | |
| 	if (linePos > 0) {	// Last line does not have ending characters
 | |
| 		lineBuffer[linePos] = '\0';
 | |
| 		ColouriseTCMDLine(lineBuffer, linePos, startLine, startPos + length - 1, keywordlists, styler);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Convert string to upper case
 | |
| static void StrUpr(char *s) {
 | |
| 	while (*s) {
 | |
| 		*s = MakeUpperCase(*s);
 | |
| 		s++;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Folding support (for DO, IFF, SWITCH, TEXT, and command groups)
 | |
| static void FoldTCMDDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler)
 | |
| {
 | |
| 	Sci_Position line = styler.GetLine(startPos);
 | |
| 	int level = styler.LevelAt(line);
 | |
| 	int levelIndent = 0;
 | |
| 	Sci_PositionU endPos = startPos + length;
 | |
| 	char s[16] = "";
 | |
| 
 | |
|     char chPrev = styler.SafeGetCharAt(startPos - 1);
 | |
| 
 | |
| 	// Scan for ( and )
 | |
| 	for (Sci_PositionU i = startPos; i < endPos; i++) {
 | |
| 
 | |
| 		int c = styler.SafeGetCharAt(i, '\n');
 | |
| 		int style = styler.StyleAt(i);
 | |
|         bool bLineStart = ((chPrev == '\r') || (chPrev == '\n')) || i == 0;
 | |
| 
 | |
| 		if (style == SCE_TCMD_OPERATOR) {
 | |
| 			// CheckFoldPoint
 | |
| 			if (c == '(') {
 | |
| 				levelIndent += 1;
 | |
| 			} else if (c == ')') {
 | |
| 				levelIndent -= 1;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
|         if (( bLineStart ) && ( style == SCE_TCMD_WORD )) {
 | |
|             for (Sci_PositionU j = 0; j < 10; j++) {
 | |
|                 if (!iswordchar(styler[i + j])) {
 | |
|                     break;
 | |
|                 }
 | |
|                 s[j] = styler[i + j];
 | |
|                 s[j + 1] = '\0';
 | |
|             }
 | |
| 
 | |
| 			StrUpr( s );
 | |
|             if ((strcmp(s, "DO") == 0) || (strcmp(s, "IFF") == 0) || (strcmp(s, "SWITCH") == 0) || (strcmp(s, "TEXT") == 0)) {
 | |
|                 levelIndent++;
 | |
|             } else if ((strcmp(s, "ENDDO") == 0) || (strcmp(s, "ENDIFF") == 0) || (strcmp(s, "ENDSWITCH") == 0) || (strcmp(s, "ENDTEXT") == 0)) {
 | |
|                 levelIndent--;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 		if (c == '\n') { // line end
 | |
| 				if (levelIndent > 0) {
 | |
| 						level |= SC_FOLDLEVELHEADERFLAG;
 | |
| 				}
 | |
| 				if (level != styler.LevelAt(line))
 | |
| 						styler.SetLevel(line, level);
 | |
| 				level += levelIndent;
 | |
| 				if ((level & SC_FOLDLEVELNUMBERMASK) < SC_FOLDLEVELBASE)
 | |
| 						level = SC_FOLDLEVELBASE;
 | |
| 				line++;
 | |
| 				// reset state
 | |
| 				levelIndent = 0;
 | |
| 				level &= ~SC_FOLDLEVELHEADERFLAG;
 | |
| 				level &= ~SC_FOLDLEVELWHITEFLAG;
 | |
| 		}
 | |
| 
 | |
| 		chPrev = c;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static const char *const tcmdWordListDesc[] = {
 | |
| 	"Internal Commands",
 | |
| 	"Aliases",
 | |
| 	0
 | |
| };
 | |
| 
 | |
| LexerModule lmTCMD(SCLEX_TCMD, ColouriseTCMDDoc, "tcmd", FoldTCMDDoc, tcmdWordListDesc);
 |