| 1 | // SciTE - Scintilla based Text Editor |
| 2 | // LexBullant.cxx - lexer for Bullant |
| 3 | |
| 4 | #include <stdlib.h> |
| 5 | #include <string.h> |
| 6 | #include <stdio.h> |
| 7 | #include <stdarg.h> |
| 8 | #include <assert.h> |
| 9 | #include <ctype.h> |
| 10 | |
| 11 | #include <string> |
| 12 | #include <string_view> |
| 13 | |
| 14 | #include "ILexer.h" |
| 15 | #include "Scintilla.h" |
| 16 | #include "SciLexer.h" |
| 17 | |
| 18 | #include "WordList.h" |
| 19 | #include "LexAccessor.h" |
| 20 | #include "Accessor.h" |
| 21 | #include "StyleContext.h" |
| 22 | #include "CharacterSet.h" |
| 23 | #include "LexerModule.h" |
| 24 | |
| 25 | using namespace Lexilla; |
| 26 | |
| 27 | static int classifyWordBullant(Sci_PositionU start, Sci_PositionU end, WordList &keywords, Accessor &styler) { |
| 28 | char s[100]; |
| 29 | s[0] = '\0'; |
| 30 | for (Sci_PositionU i = 0; i < end - start + 1 && i < 30; i++) { |
| 31 | s[i] = static_cast<char>(tolower(styler[start + i])); |
| 32 | s[i + 1] = '\0'; |
| 33 | } |
| 34 | int lev= 0; |
| 35 | char chAttr = SCE_C_IDENTIFIER; |
| 36 | if (isdigit(s[0]) || (s[0] == '.')){ |
| 37 | chAttr = SCE_C_NUMBER; |
| 38 | } |
| 39 | else { |
| 40 | if (keywords.InList(s)) { |
| 41 | chAttr = SCE_C_WORD; |
| 42 | if (strcmp(s, "end" ) == 0) |
| 43 | lev = -1; |
| 44 | else if (strcmp(s, "method" ) == 0 || |
| 45 | strcmp(s, "case" ) == 0 || |
| 46 | strcmp(s, "class" ) == 0 || |
| 47 | strcmp(s, "debug" ) == 0 || |
| 48 | strcmp(s, "test" ) == 0 || |
| 49 | strcmp(s, "if" ) == 0 || |
| 50 | strcmp(s, "lock" ) == 0 || |
| 51 | strcmp(s, "transaction" ) == 0 || |
| 52 | strcmp(s, "trap" ) == 0 || |
| 53 | strcmp(s, "until" ) == 0 || |
| 54 | strcmp(s, "while" ) == 0) |
| 55 | lev = 1; |
| 56 | } |
| 57 | } |
| 58 | styler.ColourTo(end, chAttr); |
| 59 | return lev; |
| 60 | } |
| 61 | |
| 62 | static void ColouriseBullantDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], |
| 63 | Accessor &styler) { |
| 64 | WordList &keywords = *keywordlists[0]; |
| 65 | |
| 66 | styler.StartAt(startPos); |
| 67 | |
| 68 | bool fold = styler.GetPropertyInt("fold" ) != 0; |
| 69 | Sci_Position lineCurrent = styler.GetLine(startPos); |
| 70 | int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; |
| 71 | int levelCurrent = levelPrev; |
| 72 | |
| 73 | int state = initStyle; |
| 74 | if (state == SCE_C_STRINGEOL) // Does not leak onto next line |
| 75 | state = SCE_C_DEFAULT; |
| 76 | char chPrev = ' '; |
| 77 | char chNext = styler[startPos]; |
| 78 | Sci_PositionU lengthDoc = startPos + length; |
| 79 | int visibleChars = 0; |
| 80 | styler.StartSegment(startPos); |
| 81 | int endFoundThisLine = 0; |
| 82 | for (Sci_PositionU i = startPos; i < lengthDoc; i++) { |
| 83 | char ch = chNext; |
| 84 | chNext = styler.SafeGetCharAt(i + 1); |
| 85 | |
| 86 | if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { |
| 87 | // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix) |
| 88 | // Avoid triggering two times on Dos/Win |
| 89 | // End of line |
| 90 | endFoundThisLine = 0; |
| 91 | if (state == SCE_C_STRINGEOL) { |
| 92 | styler.ColourTo(i, state); |
| 93 | state = SCE_C_DEFAULT; |
| 94 | } |
| 95 | if (fold) { |
| 96 | int lev = levelPrev; |
| 97 | if (visibleChars == 0) |
| 98 | lev |= SC_FOLDLEVELWHITEFLAG; |
| 99 | if ((levelCurrent > levelPrev) && (visibleChars > 0)) |
| 100 | lev |= SC_FOLDLEVELHEADERFLAG; |
| 101 | styler.SetLevel(lineCurrent, lev); |
| 102 | lineCurrent++; |
| 103 | levelPrev = levelCurrent; |
| 104 | } |
| 105 | visibleChars = 0; |
| 106 | |
| 107 | /* int indentBlock = GetLineIndentation(lineCurrent); |
| 108 | if (blockChange==1){ |
| 109 | lineCurrent++; |
| 110 | int pos=SetLineIndentation(lineCurrent, indentBlock + indentSize); |
| 111 | } else if (blockChange==-1) { |
| 112 | indentBlock -= indentSize; |
| 113 | if (indentBlock < 0) |
| 114 | indentBlock = 0; |
| 115 | SetLineIndentation(lineCurrent, indentBlock); |
| 116 | lineCurrent++; |
| 117 | } |
| 118 | blockChange=0; |
| 119 | */ } |
| 120 | if (!(IsASCII(ch) && isspace(ch))) |
| 121 | visibleChars++; |
| 122 | |
| 123 | if (styler.IsLeadByte(ch)) { |
| 124 | chNext = styler.SafeGetCharAt(i + 2); |
| 125 | chPrev = ' '; |
| 126 | i += 1; |
| 127 | continue; |
| 128 | } |
| 129 | |
| 130 | if (state == SCE_C_DEFAULT) { |
| 131 | if (iswordstart(ch)) { |
| 132 | styler.ColourTo(i-1, state); |
| 133 | state = SCE_C_IDENTIFIER; |
| 134 | } else if (ch == '@' && chNext == 'o') { |
| 135 | if ((styler.SafeGetCharAt(i+2) =='f') && (styler.SafeGetCharAt(i+3) == 'f')) { |
| 136 | styler.ColourTo(i-1, state); |
| 137 | state = SCE_C_COMMENT; |
| 138 | } |
| 139 | } else if (ch == '#') { |
| 140 | styler.ColourTo(i-1, state); |
| 141 | state = SCE_C_COMMENTLINE; |
| 142 | } else if (ch == '\"') { |
| 143 | styler.ColourTo(i-1, state); |
| 144 | state = SCE_C_STRING; |
| 145 | } else if (ch == '\'') { |
| 146 | styler.ColourTo(i-1, state); |
| 147 | state = SCE_C_CHARACTER; |
| 148 | } else if (isoperator(ch)) { |
| 149 | styler.ColourTo(i-1, state); |
| 150 | styler.ColourTo(i, SCE_C_OPERATOR); |
| 151 | } |
| 152 | } else if (state == SCE_C_IDENTIFIER) { |
| 153 | if (!iswordchar(ch)) { |
| 154 | int levelChange = classifyWordBullant(styler.GetStartSegment(), i - 1, keywords, styler); |
| 155 | state = SCE_C_DEFAULT; |
| 156 | chNext = styler.SafeGetCharAt(i + 1); |
| 157 | if (ch == '#') { |
| 158 | state = SCE_C_COMMENTLINE; |
| 159 | } else if (ch == '\"') { |
| 160 | state = SCE_C_STRING; |
| 161 | } else if (ch == '\'') { |
| 162 | state = SCE_C_CHARACTER; |
| 163 | } else if (isoperator(ch)) { |
| 164 | styler.ColourTo(i, SCE_C_OPERATOR); |
| 165 | } |
| 166 | if (endFoundThisLine == 0) |
| 167 | levelCurrent+=levelChange; |
| 168 | if (levelChange == -1) |
| 169 | endFoundThisLine=1; |
| 170 | } |
| 171 | } else if (state == SCE_C_COMMENT) { |
| 172 | if (ch == '@' && chNext == 'o') { |
| 173 | if (styler.SafeGetCharAt(i+2) == 'n') { |
| 174 | styler.ColourTo(i+2, state); |
| 175 | state = SCE_C_DEFAULT; |
| 176 | i+=2; |
| 177 | } |
| 178 | } |
| 179 | } else if (state == SCE_C_COMMENTLINE) { |
| 180 | if (ch == '\r' || ch == '\n') { |
| 181 | endFoundThisLine = 0; |
| 182 | styler.ColourTo(i-1, state); |
| 183 | state = SCE_C_DEFAULT; |
| 184 | } |
| 185 | } else if (state == SCE_C_STRING) { |
| 186 | if (ch == '\\') { |
| 187 | if (chNext == '\"' || chNext == '\'' || chNext == '\\') { |
| 188 | i++; |
| 189 | ch = chNext; |
| 190 | chNext = styler.SafeGetCharAt(i + 1); |
| 191 | } |
| 192 | } else if (ch == '\"') { |
| 193 | styler.ColourTo(i, state); |
| 194 | state = SCE_C_DEFAULT; |
| 195 | } else if (chNext == '\r' || chNext == '\n') { |
| 196 | endFoundThisLine = 0; |
| 197 | styler.ColourTo(i-1, SCE_C_STRINGEOL); |
| 198 | state = SCE_C_STRINGEOL; |
| 199 | } |
| 200 | } else if (state == SCE_C_CHARACTER) { |
| 201 | if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { |
| 202 | endFoundThisLine = 0; |
| 203 | styler.ColourTo(i-1, SCE_C_STRINGEOL); |
| 204 | state = SCE_C_STRINGEOL; |
| 205 | } else if (ch == '\\') { |
| 206 | if (chNext == '\"' || chNext == '\'' || chNext == '\\') { |
| 207 | i++; |
| 208 | ch = chNext; |
| 209 | chNext = styler.SafeGetCharAt(i + 1); |
| 210 | } |
| 211 | } else if (ch == '\'') { |
| 212 | styler.ColourTo(i, state); |
| 213 | state = SCE_C_DEFAULT; |
| 214 | } |
| 215 | } |
| 216 | chPrev = ch; |
| 217 | } |
| 218 | styler.ColourTo(lengthDoc - 1, state); |
| 219 | |
| 220 | // Fill in the real level of the next line, keeping the current flags as they will be filled in later |
| 221 | if (fold) { |
| 222 | int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; |
| 223 | //styler.SetLevel(lineCurrent, levelCurrent | flagsNext); |
| 224 | styler.SetLevel(lineCurrent, levelPrev | flagsNext); |
| 225 | |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | static const char * const bullantWordListDesc[] = { |
| 230 | "Keywords" , |
| 231 | 0 |
| 232 | }; |
| 233 | |
| 234 | LexerModule lmBullant(SCLEX_BULLANT, ColouriseBullantDoc, "bullant" , 0, bullantWordListDesc); |
| 235 | |