void SCI_METHOD LexerBaan::Fold()

in ext/scintilla/lexers/LexBaan.cxx [729:986]


void SCI_METHOD LexerBaan::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
	if (!options.fold)
		return;

	char word[100];
	int wordlen = 0;
	bool foldStart = true;
	bool foldNextSelect = true;
	bool afterFunctionSection = false;
	bool beforeDeclarationSection = false;
	int currLineStyle = 0;
	int nextLineStyle = 0;

	std::string startTags[6] = { "for", "if", "on", "repeat", "select", "while" };
	std::string endTags[6] = { "endcase", "endfor", "endif", "endselect", "endwhile", "until" };
	std::string selectCloseTags[5] = { "selectdo", "selecteos", "selectempty", "selecterror", "endselect" };

	LexAccessor styler(pAccess);
	Sci_PositionU endPos = startPos + length;
	int visibleChars = 0;
	Sci_Position lineCurrent = styler.GetLine(startPos);

	// Backtrack to previous line in case need to fix its fold status
	if (startPos > 0) {
		if (lineCurrent > 0) {
			lineCurrent--;
			startPos = styler.LineStart(lineCurrent);
		}
	}

	int levelPrev = SC_FOLDLEVELBASE;
	if (lineCurrent > 0)
		levelPrev = styler.LevelAt(lineCurrent - 1) >> 16;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int style = initStyle;
	int styleNext = styler.StyleAt(startPos);

	for (Sci_PositionU i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		int stylePrev = (i) ? styler.StyleAt(i - 1) : SCE_BAAN_DEFAULT;
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');

		// Comment folding
		if (options.foldComment && style == SCE_BAAN_COMMENTDOC) {
			if (style != stylePrev) {
				levelCurrent++;
			}
			else if (style != styleNext) {
				levelCurrent--;
			}
		}
		if (options.foldComment && atEOL && IsCommentLine(lineCurrent, styler)) {
			if (!IsCommentLine(lineCurrent - 1, styler)
				&& IsCommentLine(lineCurrent + 1, styler))
				levelCurrent++;
			else if (IsCommentLine(lineCurrent - 1, styler)
				&& !IsCommentLine(lineCurrent + 1, styler))
				levelCurrent--;
		}
		// PreProcessor Folding
		if (options.foldPreprocessor) {
			if (atEOL && IsPreProcLine(lineCurrent, styler)) {
				if (!IsPreProcLine(lineCurrent - 1, styler)
					&& IsPreProcLine(lineCurrent + 1, styler))
					levelCurrent++;
				else if (IsPreProcLine(lineCurrent - 1, styler)
					&& !IsPreProcLine(lineCurrent + 1, styler))
					levelCurrent--;
			}
			else if (style == SCE_BAAN_PREPROCESSOR) {
				// folds #ifdef/#if/#ifndef - they are not part of the IsPreProcLine folding.
				if (ch == '#') {
					if (styler.Match(i, "#ifdef") || styler.Match(i, "#if") || styler.Match(i, "#ifndef")
						|| styler.Match(i, "#context_on"))
						levelCurrent++;
					else if (styler.Match(i, "#endif") || styler.Match(i, "#context_off"))
						levelCurrent--;
				}
			}
		}
		//Syntax Folding
		if (options.baanFoldSyntaxBased && (style == SCE_BAAN_OPERATOR)) {
			if (ch == '{' || ch == '(') {
				levelCurrent++;
			}
			else if (ch == '}' || ch == ')') {
				levelCurrent--;
			}
		}
		//Keywords Folding
		if (options.baanFoldKeywordsBased) {
			if (atEOL && IsDeclarationLine(lineCurrent, styler)) {
				if (!IsDeclarationLine(lineCurrent - 1, styler)
					&& IsDeclarationLine(lineCurrent + 1, styler))
					levelCurrent++;
				else if (IsDeclarationLine(lineCurrent - 1, styler)
					&& !IsDeclarationLine(lineCurrent + 1, styler))
					levelCurrent--;
			}
			else if (style == SCE_BAAN_WORD) {
				word[wordlen++] = static_cast<char>(MakeLowerCase(ch));
				if (wordlen == 100) {                   // prevent overflow
					word[0] = '\0';
					wordlen = 1;
				}
				if (styleNext != SCE_BAAN_WORD) {
					word[wordlen] = '\0';
					wordlen = 0;
					if (strcmp(word, "for") == 0) {
						Sci_PositionU j = i + 1;
						while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
							j++;
						}
						if (styler.Match(j, "update")) {
							// Means this is a "for update" used by Select which is already folded.
							foldStart = false;
						}
					}
					else if (strcmp(word, "on") == 0) {
						Sci_PositionU j = i + 1;
						while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
							j++;
						}
						if (!styler.Match(j, "case")) {
							// Means this is not a "on Case" statement... could be "on" used by index.
							foldStart = false;
						}
					}
					else if (strcmp(word, "select") == 0) {
						if (foldNextSelect) {
							// Next Selects are sub-clause till reach of selectCloseTags[] array.
							foldNextSelect = false;
							foldStart = true;
						}
						else {
							foldNextSelect = false;
							foldStart = false;
						}
					}
					else if (wordInArray(word, selectCloseTags, 5)) {
						// select clause ends, next select clause can be folded.
						foldNextSelect = true;
						foldStart = true;
					}
					else {
						foldStart = true;
					}
					if (foldStart) {
						if (wordInArray(word, startTags, 6)) {
							levelCurrent++;
						}
						else if (wordInArray(word, endTags, 6)) {
							levelCurrent--;
						}
					}
				}
			}
		}
		// Fold inner level of if/select/case statements
		if (options.baanFoldInnerLevel && atEOL) {
			bool currLineInnerLevel = IsInnerLevelFold(lineCurrent, styler);
			bool nextLineInnerLevel = IsInnerLevelFold(lineCurrent + 1, styler);
			if (currLineInnerLevel && currLineInnerLevel != nextLineInnerLevel) {
				levelCurrent++;
			}
			else if (nextLineInnerLevel && nextLineInnerLevel != currLineInnerLevel) {
				levelCurrent--;
			}
		}
		// Section Foldings.
		// One way of implementing Section Foldings, as there is no END markings of sections.
		// first section ends on the previous line of next section.
		// Re-written whole folding to accomodate this.
		if (options.baanFoldSections && atEOL) {
			currLineStyle = mainOrSubSectionLine(lineCurrent, styler);
			nextLineStyle = mainOrSubSectionLine(lineCurrent + 1, styler);
			if (currLineStyle != 0 && currLineStyle != nextLineStyle) {
				if (levelCurrent < levelPrev)
					--levelPrev;
				for (Sci_Position j = styler.LineStart(lineCurrent); j < styler.LineStart(lineCurrent + 1) - 1; j++) {
					if (IsASpaceOrTab(styler[j]))
						continue;
					else if (styler.StyleAt(j) == SCE_BAAN_WORD5) {
						if (styler.Match(j, "functions:")) {
							// Means functions: is the end of MainSections.
							// Nothing to fold after this.
							afterFunctionSection = true;
							break;
						}
						else {
							afterFunctionSection = false;
							break;
						}
					}
					else {
						afterFunctionSection = false;
						break;
					}
				}
				if (!afterFunctionSection)
					levelCurrent++;
			}
			else if (nextLineStyle != 0 && currLineStyle != nextLineStyle
				&& (priorSectionIsSubSection(lineCurrent -1 ,styler)
					|| !nextSectionIsSubSection(lineCurrent + 1, styler))) {
				for (Sci_Position j = styler.LineStart(lineCurrent + 1); j < styler.LineStart(lineCurrent + 1 + 1) - 1; j++) {
					if (IsASpaceOrTab(styler[j]))
						continue;
					else if (styler.StyleAt(j) == SCE_BAAN_WORD5) {
						if (styler.Match(j, "declaration:")) {
							// Means declaration: is the start of MainSections.
							// Nothing to fold before this.
							beforeDeclarationSection = true;
							break;
						}
						else {
							beforeDeclarationSection = false;
							break;
						}
					}
					else {
						beforeDeclarationSection = false;
						break;
					}
				}
				if (!beforeDeclarationSection) {
					levelCurrent--;
					if (nextLineStyle == SCE_BAAN_WORD5 && priorSectionIsSubSection(lineCurrent-1, styler))
						// next levelCurrent--; is to unfold previous subsection fold.
						// On reaching the next main section, the previous main as well sub section ends.
						levelCurrent--;
				}
			}
		}
		if (atEOL) {
			int lev = levelPrev;
			lev |= levelCurrent << 16;
			if (visibleChars == 0 && options.foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}