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++;
}
}