void SCI_METHOD LexerVerilog::Fold()

in ext/scintilla/lexers/LexVerilog.cxx [790:1038]


void SCI_METHOD LexerVerilog::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess)
{
	LexAccessor styler(pAccess);
	bool foldAtBrace  = 1;
	bool foldAtParenthese  = 1;

	Sci_Position lineCurrent = styler.GetLine(startPos);
	// Move back one line to be compatible with LexerModule::Fold behavior, fixes problem with foldComment behavior
	if (lineCurrent > 0) {
		lineCurrent--;
		Sci_Position newStartPos = styler.LineStart(lineCurrent);
		length += startPos - newStartPos;
		startPos = newStartPos;
		initStyle = 0;
		if (startPos > 0) {
			initStyle = styler.StyleAt(startPos - 1);
		}
	}
	Sci_PositionU endPos = startPos + length;
	int visibleChars = 0;
	int levelCurrent = SC_FOLDLEVELBASE;
	if (lineCurrent > 0)
		levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
	int levelMinCurrent = levelCurrent;
	int levelNext = levelCurrent;
	char chNext = styler[startPos];
	int styleNext = MaskActive(styler.StyleAt(startPos));
	int style = MaskActive(initStyle);

	// restore fold state (if it exists) for prior line
	int stateCurrent = 0;
	std::map<Sci_Position,int>::iterator foldStateIterator = foldState.find(lineCurrent-1);
	if (foldStateIterator != foldState.end()) {
		stateCurrent = foldStateIterator->second;
	}

	// remove all foldState entries after lineCurrent-1
	foldStateIterator = foldState.upper_bound(lineCurrent-1);
	if (foldStateIterator != foldState.end()) {
		foldState.erase(foldStateIterator, foldState.end());
	}

	for (Sci_PositionU i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int stylePrev = style;
		style = styleNext;
		styleNext = MaskActive(styler.StyleAt(i + 1));
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (!(stateCurrent & protectedFlag)) {
			if (options.foldComment && IsStreamCommentStyle(style)) {
				if (!IsStreamCommentStyle(stylePrev)) {
					levelNext++;
				} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
					// Comments don't end at end of line and the next character may be unstyled.
					levelNext--;
				}
			}
			if (options.foldComment && atEOL && IsCommentLine(lineCurrent, styler))
			{
				if (!IsCommentLine(lineCurrent - 1, styler)
					&& IsCommentLine(lineCurrent + 1, styler))
					levelNext++;
				else if (IsCommentLine(lineCurrent - 1, styler)
						 && !IsCommentLine(lineCurrent+1, styler))
					levelNext--;
			}
			if (options.foldComment && (style == SCE_V_COMMENTLINE)) {
				if ((ch == '/') && (chNext == '/')) {
					char chNext2 = styler.SafeGetCharAt(i + 2);
					if (chNext2 == '{') {
						levelNext++;
					} else if (chNext2 == '}') {
						levelNext--;
					}
				}
			}
		}
		if (ch == '`') {
			Sci_PositionU j = i + 1;
			while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
				j++;
			}
			if (styler.Match(j, "protected")) {
				stateCurrent |= protectedFlag;
				levelNext++;
			} else if (styler.Match(j, "endprotected")) {
				stateCurrent &= ~protectedFlag;
				levelNext--;
			} else if (!(stateCurrent & protectedFlag) && options.foldPreprocessor && (style == SCE_V_PREPROCESSOR)) {
				if (styler.Match(j, "if")) {
					if (options.foldPreprocessorElse) {
						// Measure the minimum before a begin to allow
						// folding on "end else begin"
						if (levelMinCurrent > levelNext) {
							levelMinCurrent = levelNext;
						}
					}
					levelNext++;
				} else if (options.foldPreprocessorElse && styler.Match(j, "else")) {
					levelNext--;
					if (levelMinCurrent > levelNext) {
						levelMinCurrent = levelNext;
					}
					levelNext++;
				} else if (options.foldPreprocessorElse && styler.Match(j, "elsif")) {
					levelNext--;
					// Measure the minimum before a begin to allow
					// folding on "end else begin"
					if (levelMinCurrent > levelNext) {
						levelMinCurrent = levelNext;
					}
					levelNext++;
				} else if (styler.Match(j, "endif")) {
					levelNext--;
				}
			}
		}
		if (style == SCE_V_OPERATOR) {
			if (foldAtParenthese) {
				if (ch == '(') {
					levelNext++;
				} else if (ch == ')') {
					levelNext--;
				}
			}
			// semicolons terminate external declarations
			if (ch == ';') {
				// extern and pure virtual declarations terminated by semicolon
				if (stateCurrent & foldExternFlag) {
					levelNext--;
					stateCurrent &= ~foldExternFlag;
				}
				// wait and disable statements terminated by semicolon
				if (stateCurrent & foldWaitDisableFlag) {
					stateCurrent &= ~foldWaitDisableFlag;
				}
				// typedef statements terminated by semicolon
				if (stateCurrent & typedefFlag) {
					stateCurrent &= ~typedefFlag;
				}
			}
			// wait and disable statements containing '(' will not contain "fork" keyword, special processing is not needed
			if (ch == '(') {
				if (stateCurrent & foldWaitDisableFlag) {
					stateCurrent &= ~foldWaitDisableFlag;
				}
			}
		}
		if (style == SCE_V_OPERATOR) {
			if (foldAtBrace) {
				if (ch == '{') {
					levelNext++;
				} else if (ch == '}') {
					levelNext--;
				}
			}
		}
		if (style == SCE_V_WORD && stylePrev != SCE_V_WORD) {
			Sci_PositionU j = i;
			if (styler.Match(j, "case") ||
				styler.Match(j, "casex") ||
				styler.Match(j, "casez") ||
				styler.Match(j, "covergroup") ||
				styler.Match(j, "function") ||
				styler.Match(j, "generate") ||
				styler.Match(j, "interface") ||
				styler.Match(j, "package") ||
				styler.Match(j, "primitive") ||
				styler.Match(j, "program") ||
				styler.Match(j, "sequence") ||
				styler.Match(j, "specify") ||
				styler.Match(j, "table") ||
				styler.Match(j, "task") ||
				(styler.Match(j, "module") && options.foldAtModule)) {
				levelNext++;
			} else if (styler.Match(j, "begin")) {
				// Measure the minimum before a begin to allow
				// folding on "end else begin"
				if (levelMinCurrent > levelNext) {
					levelMinCurrent = levelNext;
				}
				levelNext++;
			} else if (styler.Match(j, "class")) {
				// class does not introduce a block when used in a typedef statement
				if (!(stateCurrent & typedefFlag))
					levelNext++;
			} else if (styler.Match(j, "fork")) {
				// fork does not introduce a block when used in a wait or disable statement
				if (stateCurrent & foldWaitDisableFlag) {
					stateCurrent &= ~foldWaitDisableFlag;
				} else
					levelNext++;
			} else if (styler.Match(j, "endcase") ||
				styler.Match(j, "endclass") ||
				styler.Match(j, "endfunction") ||
				styler.Match(j, "endgenerate") ||
				styler.Match(j, "endgroup") ||
				styler.Match(j, "endinterface") ||
				styler.Match(j, "endpackage") ||
				styler.Match(j, "endprimitive") ||
				styler.Match(j, "endprogram") ||
				styler.Match(j, "endsequence") ||
				styler.Match(j, "endspecify") ||
				styler.Match(j, "endtable") ||
				styler.Match(j, "endtask") ||
				styler.Match(j, "join") ||
				styler.Match(j, "join_any") ||
				styler.Match(j, "join_none") ||
				(styler.Match(j, "endmodule") && options.foldAtModule) ||
				(styler.Match(j, "end") && !IsAWordChar(styler.SafeGetCharAt(j + 3)))) {
				levelNext--;
			} else if (styler.Match(j, "extern") ||
				styler.Match(j, "pure")) {
				// extern and pure virtual functions/tasks are terminated by ';' not endfunction/endtask
				stateCurrent |= foldExternFlag;
			} else if (styler.Match(j, "disable") ||
				styler.Match(j, "wait")) {
				// fork does not introduce a block when used in a wait or disable statement
				stateCurrent |= foldWaitDisableFlag;
			} else if (styler.Match(j, "typedef")) {
				stateCurrent |= typedefFlag;
			}
		}
		if (atEOL) {
			int levelUse = levelCurrent;
			if (options.foldAtElse||options.foldPreprocessorElse) {
				levelUse = levelMinCurrent;
			}
			int lev = levelUse | levelNext << 16;
			if (visibleChars == 0 && options.foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if (levelUse < levelNext)
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (stateCurrent) {
				foldState[lineCurrent] = stateCurrent;
			}
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelCurrent = levelNext;
			levelMinCurrent = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
}