diff options
author | nyamatongwe <devnull@localhost> | 2011-02-13 10:55:42 +1100 |
---|---|---|
committer | nyamatongwe <devnull@localhost> | 2011-02-13 10:55:42 +1100 |
commit | 40d6d4f69c35c84a0bf4c6a3316754dba4484e4e (patch) | |
tree | bab05faa30a062e1d3f4f547ff301c9d6363b362 /lexers/LexAsm.cxx | |
parent | 9bf6e65bbe0af1e39c2986ed0e522cba753662b5 (diff) | |
download | scintilla-mirror-40d6d4f69c35c84a0bf4c6a3316754dba4484e4e.tar.gz |
Folding features added by Udo Lechner.
Explicit fold points which can be set to arbitrary strings and occur anywhere.
Can choose whether to have syntax based folding and multiline comment folding.
Diffstat (limited to 'lexers/LexAsm.cxx')
-rw-r--r-- | lexers/LexAsm.cxx | 191 |
1 files changed, 183 insertions, 8 deletions
diff --git a/lexers/LexAsm.cxx b/lexers/LexAsm.cxx index b00420945..47ed4bb86 100644 --- a/lexers/LexAsm.cxx +++ b/lexers/LexAsm.cxx @@ -4,17 +4,17 @@ ** Written by The Black Horus ** Enhancements and NASM stuff by Kein-Hong Man, 2003-10 ** SCE_ASM_COMMENTBLOCK and SCE_ASM_CHARACTER are for future GNU as colouring - ** Converted to lexer object by "Udo Lechner" <dlchnr(at)gmx(dot)net> + ** Converted to lexer object and added further folding features/properties by "Udo Lechner" <dlchnr(at)gmx(dot)net> **/ // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org> // The License.txt file describes the conditions under which this software may be distributed. #include <stdlib.h> #include <string.h> -#include <ctype.h> #include <stdio.h> #include <stdarg.h> #include <assert.h> +#include <ctype.h> #ifdef _MSC_VER #pragma warning(disable: 4786) @@ -22,6 +22,7 @@ #include <string> #include <map> +#include <set> #include "ILexer.h" #include "Scintilla.h" @@ -29,7 +30,6 @@ #include "WordList.h" #include "LexAccessor.h" -#include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" @@ -62,11 +62,39 @@ static inline bool IsAsmOperator(const int ch) { return false; } +static bool IsStreamCommentStyle(int style) { + return style == SCE_ASM_COMMENTDIRECTIVE || style == SCE_ASM_COMMENTBLOCK; +} + +static inline int LowerCase(int c) { + if (c >= 'A' && c <= 'Z') + return 'a' + c - 'A'; + return c; +} + // An individual named option for use in an OptionSet // Options used for LexerAsm struct OptionsAsm { + std::string delimiter; + bool fold; + bool foldSyntaxBased; + bool foldCommentMultiline; + bool foldCommentExplicit; + std::string foldExplicitStart; + std::string foldExplicitEnd; + bool foldExplicitAnywhere; + bool foldCompact; OptionsAsm() { + delimiter = ""; + fold = false; + foldSyntaxBased = true; + foldCommentMultiline = false; + foldCommentExplicit = false; + foldExplicitStart = ""; + foldExplicitEnd = ""; + foldExplicitAnywhere = false; + foldCompact = true; } }; @@ -77,11 +105,40 @@ static const char * const asmWordListDesc[] = { "Directives", "Directive operands", "Extended instructions", + "Directives4Foldstart", + "Directives4Foldend", 0 }; struct OptionSetAsm : public OptionSet<OptionsAsm> { OptionSetAsm() { + DefineProperty("lexer.asm.comment.delimiter", &OptionsAsm::delimiter, + "Character used for COMMENT directive's delimiter, replacing the standard \"~\"."); + + DefineProperty("fold", &OptionsAsm::fold); + + DefineProperty("fold.asm.syntax.based", &OptionsAsm::foldSyntaxBased, + "Set this property to 0 to disable syntax based folding."); + + DefineProperty("fold.asm.comment.multiline", &OptionsAsm::foldCommentMultiline, + "Set this property to 1 to enable folding multi-line comments."); + + DefineProperty("fold.asm.comment.explicit", &OptionsAsm::foldCommentExplicit, + "This option enables folding explicit fold points when using the Asm lexer. " + "Explicit fold points allows adding extra folding by placing a ;{ comment at the start and a ;} " + "at the end of a section that should fold."); + + DefineProperty("fold.asm.explicit.start", &OptionsAsm::foldExplicitStart, + "The string to use for explicit fold start points, replacing the standard ;{."); + + DefineProperty("fold.asm.explicit.end", &OptionsAsm::foldExplicitEnd, + "The string to use for explicit fold end points, replacing the standard ;}."); + + DefineProperty("fold.asm.explicit.anywhere", &OptionsAsm::foldExplicitAnywhere, + "Set this property to 1 to enable explicit fold points anywhere, not just in line comments."); + + DefineProperty("fold.compact", &OptionsAsm::foldCompact); + DefineWordListSets(asmWordListDesc); } }; @@ -93,6 +150,8 @@ class LexerAsm : public ILexer { WordList directive; WordList directiveOperand; WordList extInstruction; + WordList directives4foldstart; + WordList directives4foldend; OptionsAsm options; OptionSetAsm osAsm; public: @@ -160,6 +219,12 @@ int SCI_METHOD LexerAsm::WordListSet(int n, const char *wl) { case 5: wordListN = &extInstruction; break; + case 6: + wordListN = &directives4foldstart; + break; + case 7: + wordListN = &directives4foldend; + break; } int firstModification = -1; if (wordListN) { @@ -208,7 +273,7 @@ void SCI_METHOD LexerAsm::Lex(unsigned int startPos, int length, int initStyle, if (!IsAsmOperator(sc.ch)) { sc.SetState(SCE_ASM_DEFAULT); } - }else if (sc.state == SCE_ASM_NUMBER) { + } else if (sc.state == SCE_ASM_NUMBER) { if (!IsAWordChar(sc.ch)) { sc.SetState(SCE_ASM_DEFAULT); } @@ -216,6 +281,7 @@ void SCI_METHOD LexerAsm::Lex(unsigned int startPos, int length, int initStyle, if (!IsAWordChar(sc.ch) ) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); + bool IsDirective = false; if (cpuInstruction.InList(s)) { sc.ChangeState(SCE_ASM_CPUINSTRUCTION); @@ -225,15 +291,32 @@ void SCI_METHOD LexerAsm::Lex(unsigned int startPos, int length, int initStyle, sc.ChangeState(SCE_ASM_REGISTER); } else if (directive.InList(s)) { sc.ChangeState(SCE_ASM_DIRECTIVE); + IsDirective = true; } else if (directiveOperand.InList(s)) { sc.ChangeState(SCE_ASM_DIRECTIVEOPERAND); } else if (extInstruction.InList(s)) { sc.ChangeState(SCE_ASM_EXTINSTRUCTION); } sc.SetState(SCE_ASM_DEFAULT); + if (IsDirective && !strcmp(s, "comment")) { + char delimiter = options.delimiter.empty() ? '~' : options.delimiter.c_str()[0]; + while (IsASpaceOrTab(sc.ch) && !sc.atLineEnd) { + sc.ForwardSetState(SCE_ASM_DEFAULT); + } + if (sc.ch == delimiter) { + sc.SetState(SCE_ASM_COMMENTDIRECTIVE); + } + } } - } - else if (sc.state == SCE_ASM_COMMENT ) { + } else if (sc.state == SCE_ASM_COMMENTDIRECTIVE) { + char delimiter = options.delimiter.empty() ? '~' : options.delimiter.c_str()[0]; + if (sc.ch == delimiter) { + while (!sc.atLineEnd) { + sc.Forward(); + } + sc.SetState(SCE_ASM_DEFAULT); + } + } else if (sc.state == SCE_ASM_COMMENT ) { if (sc.atLineEnd) { sc.SetState(SCE_ASM_DEFAULT); } @@ -282,9 +365,101 @@ void SCI_METHOD LexerAsm::Lex(unsigned int startPos, int length, int initStyle, sc.Complete(); } -void SCI_METHOD LexerAsm::Fold(unsigned int /* startPos */, int /* length */, int /* initStyle */, IDocument* /* pAccess */) { +// Store both the current line's fold level and the next lines in the +// level store to make it easy to pick up with each increment +// and to make it possible to fiddle the current level for "else". + +void SCI_METHOD LexerAsm::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { - return; + if (!options.fold) + return; + + LexAccessor styler(pAccess); + + unsigned int endPos = startPos + length; + int visibleChars = 0; + int lineCurrent = styler.GetLine(startPos); + 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 = styler.StyleAt(startPos); + int style = initStyle; + char word[100]; + int wordlen = 0; + const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty(); + 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 (options.foldCommentMultiline && 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.foldCommentExplicit && ((style == SCE_ASM_COMMENT) || options.foldExplicitAnywhere)) { + if (userDefinedFoldMarkers) { + if (styler.Match(i, options.foldExplicitStart.c_str())) { + levelNext++; + } else if (styler.Match(i, options.foldExplicitEnd.c_str())) { + levelNext--; + } + } else { + if (ch == ';') { + if (chNext == '{') { + levelNext++; + } else if (chNext == '}') { + levelNext--; + } + } + } + } + if (options.foldSyntaxBased && (style == SCE_ASM_DIRECTIVE)) { + word[wordlen++] = static_cast<char>(LowerCase(ch)); + if (wordlen == 100) { // prevent overflow + word[0] = '\0'; + wordlen = 1; + } + if (styleNext != SCE_ASM_DIRECTIVE) { // reading directive ready + word[wordlen] = '\0'; + wordlen = 0; + if (directives4foldstart.InList(word)) { + levelNext++; + } else if (directives4foldend.InList(word)){ + levelNext--; + } + } + } + if (!IsASpace(ch)) + visibleChars++; + if (atEOL || (i == endPos-1)) { + int levelUse = levelCurrent; + int lev = levelUse | levelNext << 16; + if (visibleChars == 0 && options.foldCompact) + lev |= SC_FOLDLEVELWHITEFLAG; + if (levelUse < levelNext) + lev |= SC_FOLDLEVELHEADERFLAG; + if (lev != styler.LevelAt(lineCurrent)) { + styler.SetLevel(lineCurrent, lev); + } + lineCurrent++; + levelCurrent = levelNext; + levelMinCurrent = levelCurrent; + if (atEOL && (i == static_cast<unsigned int>(styler.Length()-1))) { + // There is an empty line at end of file so give it same level and empty + styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG); + } + visibleChars = 0; + } + } } LexerModule lmAsm(SCLEX_ASM, LexerAsm::LexerFactoryAsm, "asm", asmWordListDesc); |