diff options
author | nyamatongwe <unknown> | 2002-11-08 23:32:26 +0000 |
---|---|---|
committer | nyamatongwe <unknown> | 2002-11-08 23:32:26 +0000 |
commit | acc2ca9bc97b5469b53df8ffa7db1519b43d3072 (patch) | |
tree | 0b946a7a0812469e7fd3bcc42dde7ba34a331c6a | |
parent | 6d19142a58b6820750096c2b99af987bc38c53f2 (diff) | |
download | scintilla-mirror-acc2ca9bc97b5469b53df8ffa7db1519b43d3072.tar.gz |
Patch to add fold level boxing from Wilhelm Pflueger.
-rw-r--r-- | include/Scintilla.h | 10 | ||||
-rw-r--r-- | include/Scintilla.iface | 14 | ||||
-rw-r--r-- | src/Editor.cxx | 58 | ||||
-rw-r--r-- | src/LexCPP.cxx | 280 |
4 files changed, 332 insertions, 30 deletions
diff --git a/include/Scintilla.h b/include/Scintilla.h index 3199aa20d..f81646e39 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -340,6 +340,10 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_FOLDLEVELBASE 0x400 #define SC_FOLDLEVELWHITEFLAG 0x1000 #define SC_FOLDLEVELHEADERFLAG 0x2000 +#define SC_FOLDLEVELBOXHEADERFLAG 0x4000 +#define SC_FOLDLEVELBOXFOOTERFLAG 0x8000 +#define SC_FOLDLEVELCONTRACTED 0x10000 +#define SC_FOLDLEVELUNINDENT 0x20000 #define SC_FOLDLEVELNUMBERMASK 0x0FFF #define SCI_SETFOLDLEVEL 2222 #define SCI_GETFOLDLEVEL 2223 @@ -352,6 +356,12 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_GETFOLDEXPANDED 2230 #define SCI_TOGGLEFOLD 2231 #define SCI_ENSUREVISIBLE 2232 +#define SC_FOLDFLAG_LINEBEFORE_EXPANDED 0x0002 +#define SC_FOLDFLAG_LINEBEFORE_CONTRACTED 0x0004 +#define SC_FOLDFLAG_LINEAFTER_EXPANDED 0x0008 +#define SC_FOLDFLAG_LINEAFTER_CONTRACTED 0x0010 +#define SC_FOLDFLAG_LEVELNUMBERS 0x0040 +#define SC_FOLDFLAG_BOX 0x0001 #define SCI_SETFOLDFLAGS 2233 #define SCI_ENSUREVISIBLEENFORCEPOLICY 2234 #define SCI_SETTABINDENTS 2260 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index cd1bacb70..ce6d8ea53 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -877,6 +877,10 @@ enu FoldLevel=SC_FOLDLEVEL val SC_FOLDLEVELBASE=0x400 val SC_FOLDLEVELWHITEFLAG=0x1000 val SC_FOLDLEVELHEADERFLAG=0x2000 +val SC_FOLDLEVELBOXHEADERFLAG=0x4000 +val SC_FOLDLEVELBOXFOOTERFLAG=0x8000 +val SC_FOLDLEVELCONTRACTED=0x10000 +val SC_FOLDLEVELUNINDENT=0x20000 val SC_FOLDLEVELNUMBERMASK=0x0FFF # Set the fold level of a line. @@ -914,7 +918,15 @@ fun void ToggleFold=2231(int line,) # Ensure a particular line is visible by expanding any header line hiding it. fun void EnsureVisible=2232(int line,) -# Set some debugging options for folding. +enu FoldFlag=SC_FOLDFLAG_ +val SC_FOLDFLAG_LINEBEFORE_EXPANDED=0x0002 +val SC_FOLDFLAG_LINEBEFORE_CONTRACTED=0x0004 +val SC_FOLDFLAG_LINEAFTER_EXPANDED=0x0008 +val SC_FOLDFLAG_LINEAFTER_CONTRACTED=0x0010 +val SC_FOLDFLAG_LEVELNUMBERS=0x0040 +val SC_FOLDFLAG_BOX=0x0001 + +# Set some style options for folding. fun void SetFoldFlags=2233(int flags,) # Ensure a particular line is visible by expanding any header line hiding it. diff --git a/src/Editor.cxx b/src/Editor.cxx index a3b46bf5e..76ba18565 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -1458,7 +1458,7 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { number[0] = '\0'; if (firstSubLine) sprintf(number, "%d", lineDoc + 1); - if (foldFlags & 64) + if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) sprintf(number, "%X", pdoc->GetLevel(lineDoc)); PRectangle rcNumber = rcMarker; // Right justify @@ -2190,19 +2190,61 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { ll->RestoreBracesHighlight(rangeLine, braces); bool expanded = cs.GetExpanded(lineDoc); - if ( (expanded && (foldFlags & 2)) || (!expanded && (foldFlags & 4)) ) { - if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) { + if ((foldFlags & SC_FOLDFLAG_BOX) == 0) { + // Paint the line above the fold + if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED)) + || + (!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) { + if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) { + PRectangle rcFoldLine = rcLine; + rcFoldLine.bottom = rcFoldLine.top + 1; + surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); + } + } + // Paint the line below the fold + if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED)) + || + (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) { + if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) { + PRectangle rcFoldLine = rcLine; + rcFoldLine.top = rcFoldLine.bottom - 1; + surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); + } + } + } else { + int FoldLevelCurr = (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELNUMBERMASK) - SC_FOLDLEVELBASE; + int FoldLevelPrev = (pdoc->GetLevel(lineDoc-1) & SC_FOLDLEVELNUMBERMASK) - SC_FOLDLEVELBASE; + int FoldLevelFlags = (pdoc->GetLevel(lineDoc) & ~SC_FOLDLEVELNUMBERMASK); + int indentationStep = (pdoc->indentInChars ? pdoc->indentInChars : pdoc->tabInChars); + // Draw line above fold + if ((FoldLevelPrev < FoldLevelCurr) + || + (FoldLevelFlags & SC_FOLDLEVELBOXHEADERFLAG + && + (pdoc->GetLevel(lineDoc-1) & SC_FOLDLEVELBOXFOOTERFLAG) == 0)) { PRectangle rcFoldLine = rcLine; rcFoldLine.bottom = rcFoldLine.top + 1; + rcFoldLine.left += xStart + FoldLevelCurr * vs.spaceWidth * indentationStep - 1; surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); } - } - if ( (expanded && (foldFlags & 8)) || (!expanded && (foldFlags & 16)) ) { - if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) { + + // Line below the fold (or below a contracted fold) + if (FoldLevelFlags & SC_FOLDLEVELBOXFOOTERFLAG + || + (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) { PRectangle rcFoldLine = rcLine; rcFoldLine.top = rcFoldLine.bottom - 1; + rcFoldLine.left += xStart + (FoldLevelCurr)* vs.spaceWidth * indentationStep - 1; surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); } + + PRectangle rcBoxLine = rcLine; + // Draw vertical line for every fold level + for (int i = 0; i <= FoldLevelCurr; i++) { + rcBoxLine.left = xStart + i * vs.spaceWidth * indentationStep - 1; + rcBoxLine.right = rcBoxLine.left + 1; + surface->FillRectangle(rcBoxLine, vs.styles[STYLE_DEFAULT].fore.allocated); + } } // Draw the Caret @@ -3359,10 +3401,10 @@ int Editor::KeyCommand(unsigned int iMessage) { SetLastXChosen(); break; case SCI_PAGEUP: - PageMove( -1); + PageMove(-1); break; case SCI_PAGEUPEXTEND: - PageMove( -1, true); + PageMove(-1, true); break; case SCI_PAGEDOWN: PageMove(1); diff --git a/src/LexCPP.cxx b/src/LexCPP.cxx index ab8316949..661b968cd 100644 --- a/src/LexCPP.cxx +++ b/src/LexCPP.cxx @@ -20,6 +20,9 @@ #include "Scintilla.h" #include "SciLexer.h" +#define KEYWORD_BOXHEADER 1 +#define KEYWORD_FOLDCONTRACTED 2 + static bool IsOKBeforeRE(const int ch) { return (ch == '(') || (ch == '=') || (ch == ','); } @@ -34,17 +37,17 @@ static inline bool IsAWordStart(const int ch) { static inline bool IsADoxygenChar(const int ch) { return (islower(ch) || ch == '$' || ch == '@' || - ch == '\\' || ch == '&' || ch == '<' || - ch == '>' || ch == '#' || ch == '{' || - ch == '}' || ch == '[' || ch == ']'); + ch == '\\' || ch == '&' || ch == '<' || + ch == '>' || ch == '#' || ch == '{' || + ch == '}' || ch == '[' || ch == ']'); } static inline bool IsStateComment(const int state) { return ((state == SCE_C_COMMENT) || - (state == SCE_C_COMMENTLINE) || - (state == SCE_C_COMMENTDOC) || - (state == SCE_C_COMMENTDOCKEYWORD) || - (state == SCE_C_COMMENTDOCKEYWORDERROR)); + (state == SCE_C_COMMENTLINE) || + (state == SCE_C_COMMENTDOC) || + (state == SCE_C_COMMENTDOCKEYWORD) || + (state == SCE_C_COMMENTDOCKEYWORDERROR)); } static inline bool IsStateString(const int state) { @@ -150,7 +153,7 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo } else { sc.GetCurrentLowered(s, sizeof(s)); } - if (!isspace(sc.ch) || !keywords3.InList(s+1)) { + if (!isspace(sc.ch) || !keywords3.InList(s + 1)) { sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR); } sc.SetState(SCE_C_COMMENTDOC); @@ -271,12 +274,233 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo static bool IsStreamCommentStyle(int style) { return style == SCE_C_COMMENT || - style == SCE_C_COMMENTDOC || - style == SCE_C_COMMENTDOCKEYWORD || - style == SCE_C_COMMENTDOCKEYWORDERROR; + style == SCE_C_COMMENTDOC || + style == SCE_C_COMMENTDOCKEYWORD || + style == SCE_C_COMMENTDOCKEYWORDERROR; +} + +static bool matchKeyword(unsigned int start, WordList &keywords, Accessor &styler, int keywordtype) { + bool FoundKeyword = false; + + for (unsigned int i = 0; + strlen(keywords[i]) > 0 && !FoundKeyword; + i++) { + if (atoi(keywords[i]) == keywordtype) { + FoundKeyword = styler.Match(start, ((char *)keywords[i]) + 2); + } + } + return FoundKeyword; +} + +static bool IsCommentLine(int line, Accessor &styler) { + unsigned int Pos = styler.LineStart(line); + while (styler.GetLine(Pos) == line) { + int PosStyle = styler.StyleAt(Pos); + + if ( !IsStreamCommentStyle(PosStyle) + && + PosStyle != SCE_C_COMMENTLINEDOC + && + PosStyle != SCE_C_COMMENTLINE + && + !IsASpace(styler.SafeGetCharAt(Pos)) + ) + return false; + Pos++; + } + + return true; } -static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordList *[], +static void FoldBoxCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], + Accessor &styler) { + + WordList &keywords4 = *keywordlists[3]; + + bool foldComment = styler.GetPropertyInt("fold.comment") != 0; + bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0; + bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; + bool firstLine = true; + unsigned int endPos = startPos + length; + int visibleChars = 0; + int lineCurrent = styler.GetLine(startPos); + int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; + int levelCurrent = levelPrev; + int levelPrevPrev; + int levelFlags = 0; + int levelUnindent = 0; + char chNext = styler[startPos]; + int styleNext = styler.StyleAt(startPos); + int style = initStyle; + + if (lineCurrent == 0) { + levelPrevPrev = levelPrev; + } else { + levelPrevPrev = styler.LevelAt(lineCurrent - 1) & SC_FOLDLEVELNUMBERMASK; + } + + for (unsigned int i = startPos; i < endPos; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + int stylePrev = style; + style = styleNext; + styleNext = styler.StyleAt(i + 1); + + bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); + + if (foldComment && IsStreamCommentStyle(style)) { + if (!IsStreamCommentStyle(stylePrev)) { + levelCurrent++; + } else if (!IsStreamCommentStyle(styleNext) && !atEOL) { + // Comments don't end at end of line and the next character may be unstyled. + levelCurrent--; + } + } + + if (foldComment && (style == SCE_C_COMMENTLINE)) { + if ((ch == '/') && (chNext == '/')) { + char chNext2 = styler.SafeGetCharAt(i + 2); + if (chNext2 == '{') { + levelCurrent++; + } else if (chNext2 == '}') { + levelCurrent--; + } + } + } + + if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) { + if (ch == '#') { + unsigned int j = i + 1; + while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) { + j++; + } + + if (styler.Match(j, "region") || styler.Match(j, "if")) { + levelCurrent++; + } else if (styler.Match(j, "end")) { + levelCurrent--; + } + } + } + + if (style == SCE_C_OPERATOR + || + style == SCE_C_COMMENT + || + style == SCE_C_COMMENTLINE) { + + if (ch == '{') { + levelCurrent++; + // Special handling if line has closing brace followed by opening brace. + if (levelCurrent == levelPrev) { + if (firstLine) + levelUnindent = 1; + else + levelUnindent = -1; + } + } else if (ch == '}') { + levelCurrent--; + } + } + + /* Check for fold header keyword at beginning of word */ + if ((style == SCE_C_WORD || style == SCE_C_COMMENT || style == SCE_C_COMMENTLINE) + && + (style != stylePrev)) { + if (matchKeyword(i, keywords4, styler, KEYWORD_BOXHEADER)) { + int line; + /* Loop backwards all empty or comment lines */ + for (line = lineCurrent - 1; + line >= 0 + && + levelCurrent == (styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK) + && + (styler.LevelAt(line) & SC_FOLDLEVELBOXFOOTERFLAG) == 0 + && + IsCommentLine(line, styler); + line--) { + /* just loop backwards */; + } + + line++; + /* Set Box header flag (if the previous line has no footer line) */ + if ((styler.LevelAt(line) & SC_FOLDLEVELBOXFOOTERFLAG) == 0) { + if (line == lineCurrent) { + /* in current line */ + levelFlags |= SC_FOLDLEVELBOXHEADERFLAG; + } else { + /* at top of all preceding comment lines */ + styler.SetLevel(line, styler.LevelAt(line) + | SC_FOLDLEVELBOXHEADERFLAG); + } + } + } + } + + if (matchKeyword(i, keywords4, styler, KEYWORD_FOLDCONTRACTED)) { + levelFlags |= SC_FOLDLEVELCONTRACTED; + } + + if (atEOL) { + int lev; + // Compute level correction for special case: '} else {' + if (levelUnindent < 0) { + levelPrev += levelUnindent; + } else { + levelCurrent += levelUnindent; + } + + lev = levelPrev; + if (visibleChars == 0 && foldCompact) + lev |= SC_FOLDLEVELWHITEFLAG; + // Produce additional footer line (e.g. after closed if) + if (visibleChars == 0 + && + (levelPrev < levelPrevPrev)) + lev |= SC_FOLDLEVELBOXFOOTERFLAG; + // Produce footer line at line before (special handling for '} else {' + if (levelPrev < levelPrevPrev) { + styler.SetLevel(lineCurrent - 1, + styler.LevelAt(lineCurrent - 1) | SC_FOLDLEVELBOXFOOTERFLAG); + } + // Mark the fold header (the line that is always visible) + if ((levelCurrent > levelPrev) && (visibleChars > 0)) + lev |= SC_FOLDLEVELHEADERFLAG; + // Show a footer line at end of fold + if (levelCurrent < levelPrev) + lev |= SC_FOLDLEVELBOXFOOTERFLAG; + /* Show a footer line at the end of each procedure (level == SC_FOLDLEVELBASE) */ + if ((levelPrev == SC_FOLDLEVELBASE) + && + (levelPrevPrev > SC_FOLDLEVELBASE) + && + (visibleChars == 0)) { + lev |= SC_FOLDLEVELBOXFOOTERFLAG; + } + + lev |= levelFlags; + if (lev != styler.LevelAt(lineCurrent)) { + styler.SetLevel(lineCurrent, lev); + } + + lineCurrent++; + levelPrevPrev = levelPrev; + levelPrev = levelCurrent; + levelUnindent = 0; + visibleChars = 0; + levelFlags = 0; + firstLine = false; + } + + if (!isspacechar(ch)) + visibleChars++; + } + // Fill in the real level of the next line, keeping the current flags as they will be filled in later + int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; + styler.SetLevel(lineCurrent, levelPrev | flagsNext); +} + +static void FoldNoBoxCppDoc(unsigned int startPos, int length, int initStyle, Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0; @@ -316,8 +540,8 @@ static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordLis } if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) { if (ch == '#') { - unsigned int j=i+1; - while ((j<endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) { + unsigned int j = i + 1; + while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) { j++; } if (styler.Match(j, "region") || styler.Match(j, "if")) { @@ -355,20 +579,34 @@ static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordLis styler.SetLevel(lineCurrent, levelPrev | flagsNext); } +static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], + Accessor &styler) { + + int foldFlags = styler.GetPropertyInt("fold.flags") ; + bool foldBox = ((foldFlags & SC_FOLDFLAG_BOX) == SC_FOLDFLAG_BOX); + + if (foldBox) { + FoldBoxCppDoc(startPos, length, initStyle, keywordlists, styler); + } else { + FoldNoBoxCppDoc(startPos, length, initStyle, styler); + } +} + static const char * const cppWordLists[] = { - "Primary keywords and identifiers", - "Secondary keywords and identifiers", - "Documentation comment keywords", - 0, -}; + "Primary keywords and identifiers", + "Secondary keywords and identifiers", + "Documentation comment keywords", + "Fold header keywords", + 0, + }; static void ColouriseCppDocSensitive(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], - Accessor &styler) { + Accessor &styler) { ColouriseCppDoc(startPos, length, initStyle, keywordlists, styler, true); } static void ColouriseCppDocInsensitive(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], - Accessor &styler) { + Accessor &styler) { ColouriseCppDoc(startPos, length, initStyle, keywordlists, styler, false); } |