diff options
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); |