From 17628b7dd9ebd432d38d3fcb809e694d71ad6889 Mon Sep 17 00:00:00 2001 From: zufuliu Date: Mon, 25 Feb 2019 14:39:32 +0800 Subject: [PATCH] Fix Python folding collapse isuue Fix Python folding collapse isuue by using a fold level stack. Fix #1898, close #5131 --- .../ScitillaComponent/ScintillaEditView.cpp | 72 +++++++++++++++++++ .../src/ScitillaComponent/ScintillaEditView.h | 3 + 2 files changed, 75 insertions(+) diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index e7a60d617..c1faf4140 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -1949,8 +1949,80 @@ void ScintillaEditView::bufferUpdated(Buffer * buffer, int mask) } } +bool ScintillaEditView::isFoldIndentationBased() const +{ + const auto lexer = execute(SCI_GETLEXER); + // search IndentAmount in scintilla\lexers folder + return lexer == SCLEX_PYTHON + || lexer == SCLEX_COFFEESCRIPT + || lexer == SCLEX_HASKELL + || lexer == SCLEX_NIMROD + || lexer == SCLEX_VB + || lexer == SCLEX_YAML + ; +} + +namespace { + +struct FoldLevelStack +{ + int levelCount = 0; // 1-based level number + int levelStack[MAX_FOLD_COLLAPSE_LEVEL]{}; + + void push(int level) + { + while (levelCount != 0 && level <= levelStack[levelCount - 1]) + { + --levelCount; + } + levelStack[levelCount++] = level; + } +}; + +} + +void ScintillaEditView::collapseFoldIndentationBased(int level2Collapse, bool mode) +{ + execute(SCI_COLOURISE, 0, -1); + + FoldLevelStack levelStack; + ++level2Collapse; // 1-based level number + + const int maxLine = static_cast(execute(SCI_GETLINECOUNT)); + int line = 0; + + while (line < maxLine) + { + int level = static_cast(execute(SCI_GETFOLDLEVEL, line)); + if (level & SC_FOLDLEVELHEADERFLAG) + { + level &= SC_FOLDLEVELNUMBERMASK; + // don't need the actually level number, only the relationship. + levelStack.push(level); + if (level2Collapse == levelStack.levelCount) + { + if (isFolded(line) != mode) + { + fold(line, mode); + } + // skip all children lines, required to avoid buffer overrun. + line = static_cast(execute(SCI_GETLASTCHILD, line, -1)); + } + } + ++line; + } + + runMarkers(true, 0, true, false); +} + void ScintillaEditView::collapse(int level2Collapse, bool mode) { + if (isFoldIndentationBased()) + { + collapseFoldIndentationBased(level2Collapse, mode); + return; + } + execute(SCI_COLOURISE, 0, -1); int maxLine = static_cast(execute(SCI_GETLINECOUNT)); diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h index 3dc7cb6e6..982e2f2dd 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h @@ -98,6 +98,7 @@ const int CP_GREEK = 1253; const bool fold_uncollapse = true; const bool fold_collapse = false; +#define MAX_FOLD_COLLAPSE_LEVEL 8 enum TextCase : UCHAR { @@ -559,6 +560,8 @@ public: ::MessageBox(_hSelf, TEXT("This function needs a newer OS version."), TEXT("Change Case Error"), MB_OK | MB_ICONHAND); }; + bool isFoldIndentationBased() const; + void collapseFoldIndentationBased(int level2Collapse, bool mode); void collapse(int level2Collapse, bool mode); void foldAll(bool mode); void fold(size_t line, bool mode);