18 skipped lines |
19 | | 19 | | #include "Scintilla.h" |
|
20 | | 20 | | #include "SciLexer.h" |
|
|
| | 22 | | #ifdef SCI_NAMESPACE |
| | 23 | | using namespace Scintilla; |
| | 24 | | #endif |
| | 25 | | |
| | 26 | | //XXX Identical to Perl, put in common area |
| | 27 | | static inline bool isEOLChar(char ch) { |
| | 28 | | return (ch == '\r') || (ch == '\n'); |
| | 29 | | } |
| | 30 | | |
| | 31 | | #define isSafeASCII(ch) ((unsigned int)(ch) <= 127) |
55 skipped lines |
| | 87 | | } |
| | 88 | | |
| | 89 | | // Forward declarations |
| | 90 | | static bool keywordIsAmbiguous(const char *prevWord); |
| | 91 | | static bool keywordDoStartsLoop(int pos, |
| | 92 | | Accessor &styler); |
| | 93 | | static bool keywordIsModifier(const char *word, |
| | 94 | | int pos, |
| | 95 | | Accessor &styler); |
| | 96 | | |
22 | | static void ClassifyWordRb(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, char *prevWord) { | | 97 | | static int ClassifyWordRb(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, char *prevWord) { |
|
| | 99 | | unsigned int i, j; |
24 | | bool wordIsNumber = isdigit(styler[start]) != 0; | | 100 | | unsigned int lim = end - start + 1; // num chars to copy |
| | 101 | | if (lim >= MAX_KEYWORD_LENGTH) { |
| | 102 | | lim = MAX_KEYWORD_LENGTH - 1; |
| | 103 | | } |
25 | | for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { | | 104 | | for (i = start, j = 0; j < lim; i++, j++) { |
26 | | s[i] = styler[start + i]; | | 105 | | s[j] = styler[i]; |
27 | | s[i + 1] = '\0'; | | |
|
| | 107 | | s[j] = '\0'; |
29 | | char chAttr = SCE_P_IDENTIFIER; | | 108 | | int chAttr; |
30 | | 109 | | if (0 == strcmp(prevWord, "class")) |
|
31 | | chAttr = SCE_P_CLASSNAME; | | 110 | | chAttr = SCE_RB_CLASSNAME; |
32 | | 111 | | else if (0 == strcmp(prevWord, "module")) |
|
33 | | chAttr = SCE_P_CLASSNAME; | | 112 | | chAttr = SCE_RB_MODULE_NAME; |
34 | | 113 | | else if (0 == strcmp(prevWord, "def")) |
|
35 | | chAttr = SCE_P_DEFNAME; | | 114 | | chAttr = SCE_RB_DEFNAME; |
36 | | else if (wordIsNumber) | | 115 | | else if (keywords.InList(s) && !followsDot(start - 1, styler)) { |
37 | | chAttr = SCE_P_NUMBER; | | |
38 | | else if (keywords.InList(s)) | | 116 | | if (keywordIsAmbiguous(s) |
39 | | chAttr = SCE_P_WORD; | | 117 | | && keywordIsModifier(s, start, styler)) { |
| | 118 | | |
| | 119 | | // Demoted keywords are colored as keywords, |
| | 120 | | // but do not affect changes in indentation. |
| | 121 | | // |
40 | | // make sure that dot-qualifiers inside the word are lexed correct | | 122 | | // Consider the word 'if': |
| | 123 | | // 1. <<if test ...>> : normal |
| | 124 | | // 2. <<stmt if test>> : demoted |
41 | | else for (unsigned int i = 0; i < end - start + 1; i++) { | | 125 | | // 3. <<lhs = if ...>> : normal: start a new indent level |
42 | | if (styler[start + i] == '.') { | | 126 | | // 4. <<obj.if = 10>> : color as identifer, since it follows '.' |
| | 127 | | |
| | 128 | | chAttr = SCE_RB_WORD_DEMOTED; |
| | 129 | | } else { |
| | 130 | | chAttr = SCE_RB_WORD; |
| | 131 | | } |
| | 132 | | } else |
| | 133 | | chAttr = SCE_RB_IDENTIFIER; |
43 | | styler.ColourTo(start + i - 1, chAttr); | | 134 | | styler.ColourTo(end, chAttr); |
| | 135 | | if (chAttr == SCE_RB_WORD) { |
| | 136 | | strcpy(prevWord, s); |
| | 137 | | } else { |
| | 138 | | prevWord[0] = 0; |
| | 139 | | } |
| | 140 | | return chAttr; |
| | 141 | | } |
| | 142 | | |
| | 143 | | |
| | 144 | | //XXX Identical to Perl, put in common area |
| | 145 | | static bool isMatch(Accessor &styler, int lengthDoc, int pos, const char *val) { |
| | 146 | | if ((pos + static_cast<int>(strlen(val))) >= lengthDoc) { |
| | 147 | | return false; |
| | 148 | | } |
| | 149 | | while (*val) { |
| | 150 | | if (*val != styler[pos++]) { |
44 | | styler.ColourTo(start + i, SCE_P_OPERATOR); | | 151 | | return false; |
|
| | 153 | | val++; |
|
47 | | styler.ColourTo(end, chAttr); | | |
48 | | strcpy(prevWord, s); | | 155 | | return true; |
|
|
| | 158 | | // Do Ruby better -- find the end of the line, work back, |
| | 159 | | // and then check for leading white space |
| | 160 | | |
| | 161 | | // Precondition: the here-doc target can be indented |
51 | | static bool IsRbComment(Accessor &styler, int pos, int len) { | | 162 | | static bool lookingAtHereDocDelim(Accessor &styler, |
| | 163 | | int pos, |
| | 164 | | int lengthDoc, |
| | 165 | | const char *HereDocDelim) |
| | 166 | | { |
| | 167 | | if (!isMatch(styler, lengthDoc, pos, HereDocDelim)) { |
| | 168 | | return false; |
| | 169 | | } |
| | 170 | | while (--pos > 0) { |
52 | | return len>0 && styler[pos]=='#'; | | 171 | | char ch = styler[pos]; |
| | 172 | | if (isEOLChar(ch)) { |
| | 173 | | return true; |
| | 174 | | } else if (ch != ' ' && ch != '\t') { |
| | 175 | | return false; |
| | 176 | | } |
| | 177 | | } |
| | 178 | | return false; |
|
|
| | 181 | | //XXX Identical to Perl, put in common area |
55 | | static bool IsRbStringStart(char ch, char chNext, char chNext2) { | | 182 | | static char opposite(char ch) { |
56 | | if (ch == '\'' || ch == '"') | | 183 | | if (ch == '(') |
57 | | return true; | | 184 | | return ')'; |
58 | | if (ch == 'u' || ch == 'U') { | | 185 | | if (ch == '[') |
| | 186 | | return ']'; |
59 | | if (chNext == '"' || chNext == '\'') | | 187 | | if (ch == '{') |
60 | | return true; | | 188 | | return '}'; |
61 | | if ((chNext == 'r' || chNext == 'R') && (chNext2 == '"' || chNext2 == '\'')) | | 189 | | if (ch == '<') |
| | 190 | | return '>'; |
62 | | return true; | | 191 | | return ch; |
63 | | } | | 192 | | } |
64 | | if ((ch == 'r' || ch == 'R') && (chNext == '"' || chNext == '\'')) | | 193 | | |
65 | | return true; | | 194 | | // Null transitions when we see we've reached the end |
| | 195 | | // and need to relex the curr char. |
|
| | 197 | | static void redo_char(int &i, char &ch, char &chNext, char &chNext2, |
| | 198 | | int &state) { |
| | 199 | | i--; |
| | 200 | | chNext2 = chNext; |
| | 201 | | chNext = ch; |
67 | | return false; | | 202 | | state = SCE_RB_DEFAULT; |
|
|
70 | | static bool IsRbWordStart(char ch, char chNext, char chNext2) { | | 205 | | static void advance_char(int &i, char &ch, char &chNext, char &chNext2) { |
| | 206 | | i++; |
| | 207 | | ch = chNext; |
71 | | return (iswordchar(ch) && !IsRbStringStart(ch, chNext, chNext2)); | | 208 | | chNext = chNext2; |
|
|
74 | | /* Return the state to use for the string starting at i; *nextIndex will be set to the first index following the quote(s) */ | | 211 | | // precondition: startPos points to one after the EOL char |
75 | | static int GetRbStringState(Accessor &styler, int i, int *nextIndex) { | | 212 | | static bool currLineContainsHereDelims(int& startPos, |
76 | | char ch = styler.SafeGetCharAt(i); | | |
77 | | char chNext = styler.SafeGetCharAt(i + 1); | | |
78 | | | | |
79 | | // Advance beyond r, u, or ur prefix, but bail if there are any unexpected chars | | |
80 | | if (ch == 'r' || ch == 'R') { | | |
81 | | i++; | | |
82 | | ch = styler.SafeGetCharAt(i); | | |
83 | | chNext = styler.SafeGetCharAt(i + 1); | | 213 | | Accessor &styler) { |
84 | | } | | |
85 | | else if (ch == 'u' || ch == 'U') { | | |
86 | | if (chNext == 'r' || chNext == 'R') | | 214 | | if (startPos <= 1) |
87 | | i += 2; | | 215 | | return false; |
88 | | else | | |
89 | | i += 1; | | |
90 | | ch = styler.SafeGetCharAt(i); | | |
91 | | chNext = styler.SafeGetCharAt(i + 1); | | |
92 | | } | | |
|
| | 217 | | int pos; |
| | 218 | | for (pos = startPos - 1; pos > 0; pos--) { |
| | 219 | | char ch = styler.SafeGetCharAt(pos); |
94 | | if (ch != '"' && ch != '\'') { | | 220 | | if (isEOLChar(ch)) { |
95 | | *nextIndex = i + 1; | | 221 | | // Leave the pointers where they are -- there are no |
| | 222 | | // here doc delims on the current line, even if |
| | 223 | | // the EOL isn't default style |
| | 224 | | |
| | 225 | | return false; |
| | 226 | | } else { |
| | 227 | | styler.Flush(); |
96 | | return SCE_P_DEFAULT; | | 228 | | if (actual_style(styler.StyleAt(pos)) == SCE_RB_HERE_DELIM) { |
| | 229 | | break; |
| | 230 | | } |
| | 231 | | } |
| | 232 | | } |
| | 233 | | if (pos == 0) { |
| | 234 | | return false; |
| | 235 | | } |
| | 236 | | // Update the pointers so we don't have to re-analyze the string |
| | 237 | | startPos = pos; |
| | 238 | | return true; |
97 | | } | | 239 | | } |
|
99 | | if (i>0 && styler.SafeGetCharAt(i-1) == '$') { | | |
100 | | *nextIndex = i + 1; | | |
101 | | return SCE_P_DEFAULT; | | |
102 | | } | | |
|
| | 242 | | static bool isEmptyLine(int pos, |
| | 243 | | Accessor &styler) { |
| | 244 | | int spaceFlags = 0; |
104 | | if (ch == chNext && ch == styler.SafeGetCharAt(i + 2)) { | | 245 | | int lineCurrent = styler.GetLine(pos); |
105 | | *nextIndex = i + 3; | | 246 | | int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL); |
| | 247 | | return (indentCurrent & SC_FOLDLEVELWHITEFLAG) != 0; |
| | 248 | | } |
| | 249 | | |
| | 250 | | static bool RE_CanFollowKeyword(const char *keyword) { |
| | 251 | | if (!strcmp(keyword, "and") |
| | 252 | | || !strcmp(keyword, "begin") |
| | 253 | | || !strcmp(keyword, "break") |
| | 254 | | || !strcmp(keyword, "case") |
| | 255 | | || !strcmp(keyword, "do") |
| | 256 | | || !strcmp(keyword, "else") |
3 skipped lines |
| | 260 | | || !strcmp(keyword, "return") |
| | 261 | | || !strcmp(keyword, "when") |
| | 262 | | || !strcmp(keyword, "unless") |
| | 263 | | || !strcmp(keyword, "until") |
| | 264 | | || !strcmp(keyword, "not") |
| | 265 | | || !strcmp(keyword, "or")) { |
| | 266 | | return true; |
| | 267 | | } |
| | 268 | | return false; |
| | 269 | | } |
|
107 | | if (ch == '"') | | 271 | | // Look at chars up to but not including endPos |
108 | | return SCE_P_TRIPLEDOUBLE; | | 272 | | // Don't look at styles in case we're looking forward |
109 | | else | | |
110 | | return SCE_P_TRIPLE; | | |
111 | | } else { | | |
112 | | *nextIndex = i + 1; | | |
|
| | 274 | | static int skipWhitespace(int startPos, |
| | 275 | | int endPos, |
| | 276 | | Accessor &styler) { |
| | 277 | | for (int i = startPos; i < endPos; i++) { |
| | 278 | | if (!iswhitespace(styler[i])) { |
| | 279 | | return i; |
| | 280 | | } |
| | 281 | | } |
| | 282 | | return endPos; |
| | 283 | | } |
261 skipped lines |
| | 545 | | int lineStart; |
| | 546 | | for (lineStart = styler.GetLine(pos); lineStart > 0; lineStart--) { |
| | 547 | | // Now look at the style before the previous line's EOL |
| | 548 | | pos = styler.LineStart(lineStart) - 1; |
| | 549 | | if (pos <= 10) { |
| | 550 | | lineStart = 0; |
| | 551 | | break; |
| | 552 | | } |
| | 553 | | char ch = styler.SafeGetCharAt(pos); |
| | 554 | | char chPrev = styler.SafeGetCharAt(pos - 1); |
114 | | if (ch == '"') | | 555 | | if (ch == '\n' && chPrev == '\r') { |
| | 556 | | pos--; |
| | 557 | | } |
| | 558 | | if (styler.SafeGetCharAt(pos - 1) == '\\') { |
| | 559 | | // Continuation line -- keep going |
115 | | return SCE_P_STRING; | | 560 | | } else if (actual_style(styler.StyleAt(pos)) != SCE_RB_DEFAULT) { |
| | 561 | | // Part of multi-line construct -- keep going |
116 | | else | | 562 | | } else if (currLineContainsHereDelims(pos, styler)) { |
| | 563 | | // Keep going, with pos and length now pointing |
| | 564 | | // at the end of the here-doc delimiter |
| | 565 | | } else if (skipWhiteSpace && isEmptyLine(pos, styler)) { |
| | 566 | | // Keep going |
| | 567 | | } else { |
| | 568 | | break; |
| | 569 | | } |
| | 570 | | } |
| | 571 | | pos = styler.LineStart(lineStart); |
| | 572 | | length += (startPos - pos); |
| | 573 | | startPos = pos; |
117 | | return SCE_P_CHARACTER; | | 574 | | initStyle = SCE_RB_DEFAULT; |
118 | | } | | |
|
|
121 | | 577 | | static void ColouriseRbDoc(unsigned int startPos, int length, int initStyle, |
|
122 | | 578 | | WordList *keywordlists[], Accessor &styler) { |
|
|
| | 580 | | // Lexer for Ruby often has to backtrack to start of current style to determine |
| | 581 | | // which characters are being used as quotes, how deeply nested is the |
| | 582 | | // start position and what the termination string is for here documents |
| | 583 | | |
124 | | int lengthDoc = startPos + length; | | 584 | | WordList &keywords = *keywordlists[0]; |
|
126 | | // Backtrack to previous line in case need to fix its tab whinging | | 586 | | class HereDocCls { |
127 | | if (startPos > 0) { | | 587 | | public: |
128 | | int lineCurrent = styler.GetLine(startPos); | | 588 | | int State; |
| | 589 | | // States |
| | 590 | | // 0: '<<' encountered |
| | 591 | | // 1: collect the delimiter |
| | 592 | | // 1b: text between the end of the delimiter and the EOL |
| | 593 | | // 2: here doc text (lines after the delimiter) |
| | 594 | | char Quote; // the char after '<<' |
| | 595 | | bool Quoted;// true if Quote in ('\'','"','`') |
| | 596 | | int DelimiterLength;// strlen(Delimiter) |
| | 597 | | char Delimiter[256];// the Delimiter, limit of 256: from Perl |
| | 598 | | bool CanBeIndented; |
129 | | if (lineCurrent > 0) { | | 599 | | HereDocCls() { |
130 | | startPos = styler.LineStart(lineCurrent-1); | | 600 | | State = 0; |
131 | | if (startPos == 0) | | 601 | | DelimiterLength = 0; |
132 | | initStyle = SCE_P_DEFAULT; | | 602 | | Delimiter[0] = '\0'; |
133 | | else | | |
134 | | initStyle = styler.StyleAt(startPos-1); | | 603 | | CanBeIndented = false; |
|
136 | | } | | 605 | | }; |
| | 606 | | HereDocCls HereDoc; |
|
138 | | // Ruby uses a different mask because bad indentation is marked by oring with 32 | | 608 | | class QuoteCls { |
| | 609 | | public: |
| | 610 | | int Count; |
| | 611 | | char Up; |
| | 612 | | char Down; |
| | 613 | | QuoteCls() { |
| | 614 | | this->New(); |
| | 615 | | } |
| | 616 | | void New() { |
| | 617 | | Count = 0; |
| | 618 | | Up = '\0'; |
| | 619 | | Down = '\0'; |
| | 620 | | } |
| | 621 | | void Open(char u) { |
| | 622 | | Count++; |
| | 623 | | Up = u; |
| | 624 | | Down = opposite(Up); |
| | 625 | | } |
| | 626 | | }; |
139 | | styler.StartAt(startPos, 127); | | 627 | | QuoteCls Quote; |
|
141 | | WordList &keywords = *keywordlists[0]; | | 629 | | int numDots = 0; // For numbers -- |
| | 630 | | // Don't start lexing in the middle of a num |
|
| | 632 | | synchronizeDocStart(startPos, length, initStyle, styler, // ref args |
| | 633 | | false); |
| | 634 | | |
| | 635 | | bool preferRE = true; |
143 | | int whingeLevel = styler.GetPropertyInt("tab.timmy.whinge.level"); | | 636 | | int state = initStyle; |
| | 637 | | int lengthDoc = startPos + length; |
| | 638 | | |
144 | | char prevWord[200]; | | 639 | | char prevWord[MAX_KEYWORD_LENGTH + 1]; // 1 byte for zero |
145 | | 640 | | prevWord[0] = '\0'; |
|
|
147 | | return ; | | 642 | | return; |
|
149 | | int state = initStyle & 31; | | 644 | | char chPrev = styler.SafeGetCharAt(startPos - 1); |
150 | | | | 645 | | char chNext = styler.SafeGetCharAt(startPos); |
151 | | int nextIndex = 0; | | 646 | | // Ruby uses a different mask because bad indentation is marked by oring with 32 |
152 | | char chPrev = ' '; | | |
153 | | char chPrev2 = ' '; | | |
154 | | char chNext = styler[startPos]; | | 647 | | styler.StartAt(startPos, 127); |
155 | | 648 | | styler.StartSegment(startPos); |
|
156 | | bool atStartLine = true; | | |
157 | | int spaceFlags = 0; | | |
158 | | for (int i = startPos; i < lengthDoc; i++) { | | |
159 | | | | |
160 | | if (atStartLine) { | | |
10 skipped lines |
171 | | chFlags = (spaceFlags & wsTab) ? chBad : chGood; | | |
172 | | } | | |
173 | | styler.SetFlags(chFlags, static_cast<char>(state)); | | |
174 | | atStartLine = false; | | |
175 | | } | | |
|
| | 650 | | static int q_states[] = {SCE_RB_STRING_Q, |
| | 651 | | SCE_RB_STRING_QQ, |
| | 652 | | SCE_RB_STRING_QR, |
| | 653 | | SCE_RB_STRING_QW, |
| | 654 | | SCE_RB_STRING_QW, |
| | 655 | | SCE_RB_STRING_QX}; |
| | 656 | | static const char* q_chars = "qQrwWx"; |
| | 657 | | |
| | 658 | | for (int i = startPos; i < lengthDoc; i++) { |
177 | | 659 | | char ch = chNext; |
|
178 | | 660 | | chNext = styler.SafeGetCharAt(i + 1); |
|
179 | | 661 | | char chNext2 = styler.SafeGetCharAt(i + 2); |
|
|
181 | | if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) { | | |
182 | | if ((state == SCE_P_DEFAULT) || (state == SCE_P_TRIPLE) || (state == SCE_P_TRIPLEDOUBLE)) { | | |
183 | | // Perform colourisation of white space and triple quoted strings at end of each line to allow | | |
184 | | // tab marking to work inside white space and triple quoted strings | | |
185 | | styler.ColourTo(i, state); | | |
186 | | } | | |
187 | | atStartLine = true; | | |
188 | | } | | |
189 | | | | |
190 | | if (styler.IsLeadByte(ch)) { | | 663 | | if (styler.IsLeadByte(ch)) { |
191 | | chNext = styler.SafeGetCharAt(i + 2); | | 664 | | chNext = chNext2; |
|
193 | | chPrev2 = ' '; | | |
|
|
|
| | 669 | | |
| | 670 | | // skip on DOS/Windows |
| | 671 | | //No, don't, because some things will get tagged on, |
| | 672 | | // so we won't recognize keywords, for example |
| | 673 | | #if 0 |
8 skipped lines |
| | 682 | | styler.ColourTo(i-1, state); |
| | 683 | | // Don't check for a missing quote, just jump into |
| | 684 | | // the here-doc state |
| | 685 | | state = SCE_RB_HERE_Q; |
| | 686 | | } |
|
| | 688 | | // Regular transitions |
198 | | if (state == SCE_P_STRINGEOL) { | | 689 | | if (state == SCE_RB_DEFAULT) { |
199 | | if (ch != '\r' && ch != '\n') { | | 690 | | if (isSafeDigit(ch)) { |
200 | | styler.ColourTo(i - 1, state); | | 691 | | styler.ColourTo(i - 1, state); |
201 | | state = SCE_P_DEFAULT; | | 692 | | state = SCE_RB_NUMBER; |
202 | | } | | 693 | | numDots = 0; |
203 | | } | | |
204 | | if (state == SCE_P_DEFAULT) { | | |
205 | | if (IsRbWordStart(ch, chNext, chNext2)) { | | 694 | | } else if (isHighBitChar(ch) || iswordstart(ch)) { |
206 | | styler.ColourTo(i - 1, state); | | 695 | | styler.ColourTo(i - 1, state); |
207 | | state = SCE_P_WORD; | | 696 | | state = SCE_RB_WORD; |
208 | | 697 | | } else if (ch == '#') { |
|
209 | | 698 | | styler.ColourTo(i - 1, state); |
|
210 | | state = chNext == '#' ? SCE_P_COMMENTBLOCK : SCE_P_COMMENTLINE; | | 699 | | state = SCE_RB_COMMENTLINE; |
211 | | } else if (ch == '=' && chNext == 'b') { | | 700 | | } else if (ch == '=') { |
212 | | 701 | | // =begin indicates the start of a comment (doc) block |
|
| | 702 | | if (i == 0 || isEOLChar(chPrev) |
| | 703 | | && chNext == 'b' |
| | 704 | | && styler.SafeGetCharAt(i + 2) == 'e' |
| | 705 | | && styler.SafeGetCharAt(i + 3) == 'g' |
| | 706 | | && styler.SafeGetCharAt(i + 4) == 'i' |
213 | | if(styler.SafeGetCharAt(i + 2) == 'e' && styler.SafeGetCharAt(i + 3) == 'g' && styler.SafeGetCharAt(i + 4) == 'i' && styler.SafeGetCharAt(i + 5) == 'n') { | | 707 | | && styler.SafeGetCharAt(i + 5) == 'n' |
| | 708 | | && !isSafeWordcharOrHigh(styler.SafeGetCharAt(i + 6))) { |
| | 709 | | styler.ColourTo(i - 1, state); |
| | 710 | | state = SCE_RB_POD; |
| | 711 | | } else { |
214 | | 712 | | styler.ColourTo(i - 1, state); |
|
215 | | state = SCE_P_TRIPLEDOUBLE; //SCE_C_COMMENT; | | 713 | | styler.ColourTo(i, SCE_RB_OPERATOR); |
| | 714 | | preferRE = true; |
|
217 | | } else if (IsRbStringStart(ch, chNext, chNext2)) { | | 716 | | } else if (ch == '"') { |
218 | | 717 | | styler.ColourTo(i - 1, state); |
|
219 | | state = GetRbStringState(styler, i, &nextIndex); | | 718 | | state = SCE_RB_STRING; |
| | 719 | | Quote.New(); |
| | 720 | | Quote.Open(ch); |
220 | | if (nextIndex != i + 1) { | | 721 | | } else if (ch == '\'') { |
221 | | i = nextIndex - 1; | | 722 | | styler.ColourTo(i - 1, state); |
222 | | ch = ' '; | | 723 | | state = SCE_RB_CHARACTER; |
223 | | chPrev = ' '; | | |
224 | | chNext = styler.SafeGetCharAt(i + 1); | | 724 | | Quote.New(); |
225 | | } | | 725 | | Quote.Open(ch); |
226 | | } else if (isoperator(ch)) { | | 726 | | } else if (ch == '`') { |
227 | | 727 | | styler.ColourTo(i - 1, state); |
|
| | 728 | | state = SCE_RB_BACKTICKS; |
228 | | styler.ColourTo(i, SCE_P_OPERATOR); | | 729 | | Quote.New(); |
229 | | } | | 730 | | Quote.Open(ch); |
230 | | } else if (state == SCE_P_WORD) { | | 731 | | } else if (ch == '@') { |
231 | | if (!iswordchar(ch)) { | | 732 | | // Instance or class var |
232 | | ClassifyWordRb(styler.GetStartSegment(), i - 1, keywords, styler, prevWord); | | 733 | | styler.ColourTo(i - 1, state); |
| | 734 | | if (chNext == '@') { |
| | 735 | | state = SCE_RB_CLASS_VAR; |
| | 736 | | advance_char(i, ch, chNext, chNext2); // pass by ref |
| | 737 | | } else { |
233 | | state = SCE_P_DEFAULT; | | 738 | | state = SCE_RB_INSTANCE_VAR; |
| | 739 | | } |
234 | | if (ch == '#') { | | 740 | | } else if (ch == '$') { |
| | 741 | | // Check for a builtin global |
| | 742 | | styler.ColourTo(i - 1, state); |
| | 743 | | // Recognize it bit by bit |
235 | | state = chNext == '#' ? SCE_P_COMMENTBLOCK : SCE_P_COMMENTLINE; | | 744 | | state = SCE_RB_GLOBAL; |
236 | | } else if (IsRbStringStart(ch, chNext, chNext2)) { | | 745 | | } else if (ch == '/' && preferRE) { |
| | 746 | | // Ambigous operator |
237 | | styler.ColourTo(i - 1, state); | | 747 | | styler.ColourTo(i - 1, state); |
238 | | state = GetRbStringState(styler, i, &nextIndex); | | 748 | | state = SCE_RB_REGEX; |
| | 749 | | Quote.New(); |
| | 750 | | Quote.Open(ch); |
239 | | if (nextIndex != i + 1) { | | 751 | | } else if (ch == '<' && chNext == '<' && chNext2 != '=') { |
240 | | i = nextIndex - 1; | | 752 | | |
241 | | ch = ' '; | | 753 | | // Recognise the '<<' symbol - either a here document or a binary op |
| | 754 | | styler.ColourTo(i - 1, state); |
| | 755 | | i++; |
| | 756 | | chNext = chNext2; |
| | 757 | | styler.ColourTo(i, SCE_RB_OPERATOR); |
| | 758 | | |
| | 759 | | if (! (strchr("\"\'`_-", chNext2) || isSafeAlpha(chNext2))) { |
| | 760 | | // It's definitely not a here-doc, |
| | 761 | | // based on Ruby's lexer/parser in the |
| | 762 | | // heredoc_identifier routine. |
| | 763 | | // Nothing else to do. |
110 skipped lines |
| | 874 | | } else if (ch == '%') { |
| | 875 | | styler.ColourTo(i - 1, state); |
| | 876 | | bool have_string = false; |
| | 877 | | if (strchr(q_chars, chNext) && !isSafeWordcharOrHigh(chNext2)) { |
| | 878 | | Quote.New(); |
| | 879 | | const char *hit = strchr(q_chars, chNext); |
| | 880 | | if (hit != NULL) { |
| | 881 | | state = q_states[hit - q_chars]; |
| | 882 | | Quote.Open(chNext2); |
| | 883 | | i += 2; |
242 | | chPrev = ' '; | | 884 | | ch = chNext2; |
243 | | 885 | | chNext = styler.SafeGetCharAt(i + 1); |
|
| | 886 | | have_string = true; |
| | 887 | | } |
| | 888 | | } else if (!isSafeWordcharOrHigh(chNext)) { |
| | 889 | | // Ruby doesn't allow high bit chars here, |
| | 890 | | // but the editor host might |
166 skipped lines |
| | 1057 | | HereDoc.Delimiter[HereDoc.DelimiterLength] = '\0'; |
| | 1058 | | } else { |
| | 1059 | | styler.ColourTo(i - 1, state); |
| | 1060 | | redo_char(i, ch, chNext, chNext2, state); |
| | 1061 | | preferRE = false; |
|
245 | | } else if (isoperator(ch)) { | | 1063 | | } |
246 | | styler.ColourTo(i, SCE_P_OPERATOR); | | |
247 | | } | | |
248 | | } | | |
249 | | } else { | | |
250 | | if (state == SCE_P_COMMENTLINE || state == SCE_P_COMMENTBLOCK) { | | 1064 | | if (HereDoc.DelimiterLength >= static_cast<int>(sizeof(HereDoc.Delimiter)) - 1) { |
251 | | if (ch == '\r' || ch == '\n') { | | |
252 | | 1065 | | styler.ColourTo(i - 1, state); |
|
253 | | state = SCE_P_DEFAULT; | | 1066 | | state = SCE_RB_ERROR; |
254 | | } | | |
255 | | } else if (state == SCE_P_STRING) { | | |
256 | | if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { | | |
257 | | styler.ColourTo(i - 1, state); | | |
258 | | state = SCE_P_STRINGEOL; | | |
259 | | } else if (ch == '\\') { | | |
260 | | if (chNext == '\"' || chNext == '\'' || chNext == '\\') { | | |
261 | | i++; | | |
262 | | ch = chNext; | | |
263 | | chNext = styler.SafeGetCharAt(i + 1); | | |
264 | | } | | |
265 | | } else if (ch == '\"') { | | |
266 | | styler.ColourTo(i, state); | | |
267 | | state = SCE_P_DEFAULT; | | 1067 | | preferRE = false; |
|
| | 1069 | | } |
| | 1070 | | } else if (state == SCE_RB_HERE_Q) { |
| | 1071 | | // Not needed: HereDoc.State == 2 |
| | 1072 | | // Indentable here docs: look backwards |
| | 1073 | | // Non-indentable: look forwards, like in Perl |
| | 1074 | | // |
| | 1075 | | // Why: so we can quickly resolve things like <<-" abc" |
| | 1076 | | |
| | 1077 | | if (!HereDoc.CanBeIndented) { |
| | 1078 | | if (isEOLChar(chPrev) |
37 skipped lines |
| | 1116 | | advance_char(i, ch, chNext, chNext2); |
| | 1117 | | } |
| | 1118 | | styler.ColourTo(i, state); |
| | 1119 | | state = SCE_RB_DEFAULT; |
| | 1120 | | } else { |
| | 1121 | | styler.ColourTo(i - 1, state); |
| | 1122 | | redo_char(i, ch, chNext, chNext2, state); // pass by ref |
| | 1123 | | } |
| | 1124 | | preferRE = false; |
| | 1125 | | } |
269 | | } else if (state == SCE_P_CHARACTER) { | | 1126 | | } else if (state == SCE_RB_POD) { |
| | 1127 | | // PODs end with ^=end\s, -- any whitespace can follow =end |
| | 1128 | | if (strchr(" \t\n\r", ch) != NULL |
| | 1129 | | && i > 5 |
| | 1130 | | && isEOLChar(styler[i - 5]) |
270 | | if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { | | 1131 | | && isMatch(styler, lengthDoc, i - 4, "=end")) { |
271 | | styler.ColourTo(i - 1, state); | | 1132 | | styler.ColourTo(i - 1, state); |
272 | | state = SCE_P_STRINGEOL; | | 1133 | | state = SCE_RB_DEFAULT; |
| | 1134 | | preferRE = false; |
| | 1135 | | } |
273 | | } else if (ch == '\\') { | | 1136 | | } else if (state == SCE_RB_REGEX || state == SCE_RB_STRING_QR) { |
274 | | if (chNext == '\"' || chNext == '\'' || chNext == '\\') { | | 1137 | | if (ch == '\\' && Quote.Up != '\\') { |
| | 1138 | | // Skip one |
| | 1139 | | advance_char(i, ch, chNext, chNext2); |
| | 1140 | | } else if (ch == Quote.Down) { |
| | 1141 | | Quote.Count--; |
| | 1142 | | if (Quote.Count == 0) { |
| | 1143 | | // Include the options |
| | 1144 | | while (isSafeAlpha(chNext)) { |
275 | | i++; | | 1145 | | i++; |
|
277 | | chNext = styler.SafeGetCharAt(i + 1); | | 1147 | | chNext = styler.SafeGetCharAt(i + 1); |
278 | | } | | 1148 | | } |
279 | | } else if (ch == '\'') { | | |
280 | | styler.ColourTo(i, state); | | 1149 | | styler.ColourTo(i, state); |
281 | | state = SCE_P_DEFAULT; | | 1150 | | state = SCE_RB_DEFAULT; |
282 | | } | | 1151 | | preferRE = false; |
| | 1152 | | } |
283 | | } else if (state == SCE_P_TRIPLE) { | | 1153 | | } else if (ch == Quote.Up) { |
| | 1154 | | // Only if close quoter != open quoter |
| | 1155 | | Quote.Count++; |
| | 1156 | | |
284 | | if (ch == '\'' && chPrev == '\'' && chPrev2 == '\'') { | | 1157 | | } else if (ch == '#' ) { |
| | 1158 | | //todo: distinguish comments from pound chars |
| | 1159 | | // for now, handle as comment |
285 | | styler.ColourTo(i, state); | | 1160 | | styler.ColourTo(i - 1, state); |
286 | | state = SCE_P_DEFAULT; | | 1161 | | bool inEscape = false; |
287 | | } | | |
288 | | } else if (state == SCE_P_TRIPLEDOUBLE) { | | 1162 | | while (++i < lengthDoc) { |
289 | | // =end terminates the comment block | | 1163 | | ch = styler.SafeGetCharAt(i); |
290 | | if (ch == 'd' && chPrev == 'n' && chPrev2 == 'e') { | | 1164 | | if (ch == '\\') { |
291 | | if (styler.SafeGetCharAt(i - 3) == '=') { | | 1165 | | inEscape = true; |
| | 1166 | | } else if (isEOLChar(ch)) { |
| | 1167 | | // Comment inside a regex |
292 | | styler.ColourTo(i, state); | | 1168 | | styler.ColourTo(i - 1, SCE_RB_COMMENTLINE); |
293 | | state = SCE_P_DEFAULT; | | 1169 | | break; |
294 | | } | | 1170 | | } else if (inEscape) { |
295 | | } | | 1171 | | inEscape = false; // don't look at char |
| | 1172 | | } else if (ch == Quote.Down) { |
| | 1173 | | // Have the regular handler deal with this |
| | 1174 | | // to get trailing modifiers. |
| | 1175 | | i--; |
| | 1176 | | ch = styler[i]; |
| | 1177 | | break; |
| | 1178 | | } |
| | 1179 | | } |
| | 1180 | | chNext = styler.SafeGetCharAt(i + 1); |
| | 1181 | | chNext2 = styler.SafeGetCharAt(i + 2); |
93 skipped lines |
| | 1275 | | while (--pos >= lineStartPosn) { |
| | 1276 | | style = actual_style(styler.StyleAt(pos)); |
| | 1277 | | if (style == SCE_RB_DEFAULT) { |
| | 1278 | | if (iswhitespace(ch = styler[pos])) { |
| | 1279 | | //continue |
| | 1280 | | } else if (ch == '\r' || ch == '\n') { |
| | 1281 | | // Scintilla's LineStart() and GetLine() routines aren't |
| | 1282 | | // platform-independent, so if we have text prepared with |
| | 1283 | | // a different system we can't rely on it. |
| | 1284 | | return false; |
|
| | 1286 | | } else { |
| | 1287 | | break; |
|
298 | | chPrev2 = chPrev; | | 1289 | | } |
299 | | chPrev = ch; | | 1290 | | if (pos < lineStartPosn) { |
300 | | } | | 1291 | | return false; //XXX not quite right if the prev line is a continuation |
| | 1292 | | } |
| | 1293 | | // First things where the action is unambiguous |
| | 1294 | | switch (style) { |
| | 1295 | | case SCE_RB_DEFAULT: |
| | 1296 | | case SCE_RB_COMMENTLINE: |
| | 1297 | | case SCE_RB_POD: |
| | 1298 | | case SCE_RB_CLASSNAME: |
| | 1299 | | case SCE_RB_DEFNAME: |
| | 1300 | | case SCE_RB_MODULE_NAME: |
| | 1301 | | return false; |
| | 1302 | | case SCE_RB_OPERATOR: |
| | 1303 | | break; |
301 | | if (state == SCE_P_WORD) { | | 1304 | | case SCE_RB_WORD: |
| | 1305 | | // Watch out for uses of 'else if' |
| | 1306 | | //XXX: Make a list of other keywords where 'if' isn't a modifier |
| | 1307 | | // and can appear legitimately |
| | 1308 | | // Formulate this to avoid warnings from most compilers |
| | 1309 | | if (strcmp(word, "if") == 0) { |
| | 1310 | | char prevWord[MAX_KEYWORD_LENGTH + 1]; |
| | 1311 | | getPrevWord(pos, prevWord, styler, SCE_RB_WORD); |
302 | | ClassifyWordRb(styler.GetStartSegment(), lengthDoc-1, keywords, styler, prevWord); | | 1312 | | return strcmp(prevWord, "else") != 0; |
| | 1313 | | } |
| | 1314 | | return true; |
| | 1315 | | default: |
| | 1316 | | return true; |
| | 1317 | | } |
| | 1318 | | // Assume that if the keyword follows an operator, |
| | 1319 | | // usually it's a block assignment, like |
303 | | } else { | | 1320 | | // a << if x then y else z |
| | 1321 | | |
304 | | styler.ColourTo(lengthDoc-1, state); | | 1322 | | ch = styler[pos]; |
| | 1323 | | switch (ch) { |
| | 1324 | | case ')': |
| | 1325 | | case ']': |
| | 1326 | | case '}': |
| | 1327 | | return true; |
| | 1328 | | default: |
| | 1329 | | return false; |
305 | | } | | 1330 | | } |
|
|
| | 1333 | | #define WHILE_BACKWARDS "elihw" |
| | 1334 | | #define UNTIL_BACKWARDS "litnu" |
| | 1335 | | |
| | 1336 | | // Nothing fancy -- look to see if we follow a while/until somewhere |
| | 1337 | | // on the current line |
| | 1338 | | |
308 | | static void FoldRbDoc(unsigned int startPos, int length, int initStyle, | | 1339 | | static bool keywordDoStartsLoop(int pos, |
| | 1340 | | Accessor &styler) |
| | 1341 | | { |
| | 1342 | | char ch; |
| | 1343 | | int style; |
| | 1344 | | int lineStart = styler.GetLine(pos); |
| | 1345 | | int lineStartPosn = styler.LineStart(lineStart); |
| | 1346 | | styler.Flush(); |
| | 1347 | | while (--pos >= lineStartPosn) { |
| | 1348 | | style = actual_style(styler.StyleAt(pos)); |
| | 1349 | | if (style == SCE_RB_DEFAULT) { |
| | 1350 | | if ((ch = styler[pos]) == '\r' || ch == '\n') { |
| | 1351 | | // Scintilla's LineStart() and GetLine() routines aren't |
| | 1352 | | // platform-independent, so if we have text prepared with |
| | 1353 | | // a different system we can't rely on it. |
| | 1354 | | return false; |
| | 1355 | | } |
309 | | WordList *[], Accessor &styler) { | | 1356 | | } else if (style == SCE_RB_WORD) { |
| | 1357 | | // Check for while or until, but write the word in backwards |
| | 1358 | | char prevWord[MAX_KEYWORD_LENGTH + 1]; // 1 byte for zero |
| | 1359 | | char *dst = prevWord; |
| | 1360 | | int wordLen = 0; |
310 | | int lengthDoc = startPos + length; | | 1361 | | int start_word; |
| | 1362 | | for (start_word = pos; |
| | 1363 | | start_word >= lineStartPosn && actual_style(styler.StyleAt(start_word)) == SCE_RB_WORD; |
| | 1364 | | start_word--) { |
| | 1365 | | if (++wordLen < MAX_KEYWORD_LENGTH) { |
| | 1366 | | *dst++ = styler[start_word]; |
| | 1367 | | } |
| | 1368 | | } |
| | 1369 | | *dst = 0; |
| | 1370 | | // Did we see our keyword? |
| | 1371 | | if (!strcmp(prevWord, WHILE_BACKWARDS) |
48 skipped lines |
| | 1420 | | * true undef |
| | 1421 | | |
| | 1422 | | * Always increment: |
| | 1423 | | * begin class def do for module when { |
| | 1424 | | * |
| | 1425 | | * Always decrement: |
| | 1426 | | * end } |
| | 1427 | | * |
| | 1428 | | * Increment if these start a statement |
| | 1429 | | * if unless until while -- do nothing if they're modifiers |
|
| | 1431 | | * These end a block if there's no modifier, but don't bother |
| | 1432 | | * break next redo retry return yield |
| | 1433 | | * |
| | 1434 | | * These temporarily de-indent, but re-indent |
| | 1435 | | * case else elsif ensure rescue |
| | 1436 | | * |
| | 1437 | | * This means that the folder reflects indentation rather |
| | 1438 | | * than setting it. The language-service updates indentation |
| | 1439 | | * when users type return and finishes entering de-denters. |
| | 1440 | | * |
| | 1441 | | * Later offer to fold POD, here-docs, strings, and blocks of comments |
| | 1442 | | */ |
| | 1443 | | |
| | 1444 | | static void FoldRbDoc(unsigned int startPos, int length, int initStyle, |
| | 1445 | | WordList *[], Accessor &styler) { |
| | 1446 | | const bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; |
312 | | // Backtrack to previous line in case need to fix its fold status | | 1447 | | bool foldComment = styler.GetPropertyInt("fold.comment") != 0; |
| | 1448 | | |
| | 1449 | | synchronizeDocStart(startPos, length, initStyle, styler, // ref args |
| | 1450 | | false); |
| | 1451 | | unsigned int endPos = startPos + length; |
| | 1452 | | int visibleChars = 0; |
313 | | 1453 | | int lineCurrent = styler.GetLine(startPos); |
|
314 | | if (startPos > 0) { | | |
315 | | if (lineCurrent > 0) { | | |
316 | | lineCurrent--; | | |
317 | | startPos = styler.LineStart(lineCurrent); | | |
318 | | if (startPos == 0) | | 1454 | | int levelPrev = startPos == 0 ? 0 : (styler.LevelAt(lineCurrent) |
319 | | initStyle = SCE_P_DEFAULT; | | 1455 | | & SC_FOLDLEVELNUMBERMASK |
320 | | else | | |
321 | | initStyle = styler.StyleAt(startPos-1); | | |
322 | | } | | |
323 | | } | | |
324 | | int state = initStyle & 31; | | |
325 | | int spaceFlags = 0; | | |
326 | | int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsRbComment); | | 1456 | | & ~SC_FOLDLEVELBASE); |
327 | | if ((state == SCE_P_TRIPLE) || (state == SCE_P_TRIPLEDOUBLE)) | | |
328 | | indentCurrent |= SC_FOLDLEVELWHITEFLAG; | | 1457 | | int levelCurrent = levelPrev; |
329 | | 1458 | | char chNext = styler[startPos]; |
|
| | 1459 | | int styleNext = styler.StyleAt(startPos); |
| | 1460 | | int stylePrev = startPos <= 1 ? SCE_RB_DEFAULT : styler.StyleAt(startPos - 1); |
| | 1461 | | bool buffer_ends_with_eol = false; |
330 | | for (int i = startPos; i < lengthDoc; i++) { | | 1462 | | for (unsigned int i = startPos; i < endPos; i++) { |
331 | | 1463 | | char ch = chNext; |
|
332 | | 1464 | | chNext = styler.SafeGetCharAt(i + 1); |
|
| | 1465 | | int style = styleNext; |
333 | | int style = styler.StyleAt(i) & 31; | | 1466 | | styleNext = styler.StyleAt(i + 1); |
334 | | | | |
335 | | if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) { | | 1467 | | bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); |
336 | | int lev = indentCurrent; | | |
337 | | int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsRbComment); | | |
338 | | if ((style == SCE_P_TRIPLE) || (style== SCE_P_TRIPLEDOUBLE)) | | 1468 | | if (style == SCE_RB_COMMENTLINE) { |
339 | | indentNext |= SC_FOLDLEVELWHITEFLAG; | | |
340 | | if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { | | 1469 | | if (foldComment && stylePrev != SCE_RB_COMMENTLINE) { |
341 | | // Only non whitespace lines can be headers | | |
342 | | if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) { | | 1470 | | if (chNext == '{') { |
343 | | lev |= SC_FOLDLEVELHEADERFLAG; | | 1471 | | levelCurrent++; |
344 | | } else if (indentNext & SC_FOLDLEVELWHITEFLAG) { | | |
345 | | // Line after is blank so check the next - maybe should continue further? | | |
346 | | int spaceFlags2 = 0; | | |
347 | | int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsRbComment); | | |
348 | | if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) { | | 1472 | | } else if (chNext == '}') { |
349 | | lev |= SC_FOLDLEVELHEADERFLAG; | | 1473 | | levelCurrent--; |
350 | | } | | |
|
| | 1475 | | } |
| | 1476 | | } else if (style == SCE_RB_OPERATOR) { |
| | 1477 | | if (strchr("[{(", ch)) { |
| | 1478 | | levelCurrent++; |
| | 1479 | | } else if (strchr(")}]", ch)) { |
| | 1480 | | // Don't decrement below 0 |
| | 1481 | | if (levelCurrent > 0) |
| | 1482 | | levelCurrent--; |
|
353 | | indentCurrent = indentNext; | | 1484 | | } else if (style == SCE_RB_WORD && styleNext != SCE_RB_WORD) { |
| | 1485 | | // Look at the keyword on the left and decide what to do |
| | 1486 | | char prevWord[MAX_KEYWORD_LENGTH + 1]; // 1 byte for zero |
| | 1487 | | prevWord[0] = 0; |
| | 1488 | | getPrevWord(i, prevWord, styler, SCE_RB_WORD); |
| | 1489 | | if (!strcmp(prevWord, "end")) { |
| | 1490 | | // Don't decrement below 0 |
| | 1491 | | if (levelCurrent > 0) |
| | 1492 | | levelCurrent--; |
| | 1493 | | } else if ( !strcmp(prevWord, "if") |
| | 1494 | | || !strcmp(prevWord, "def") |
9 skipped lines |
| | 1504 | | ) { |
| | 1505 | | levelCurrent++; |
| | 1506 | | } |
| | 1507 | | } |
| | 1508 | | if (atEOL) { |
| | 1509 | | int lev = levelPrev; |
| | 1510 | | if (visibleChars == 0 && foldCompact) |
| | 1511 | | lev |= SC_FOLDLEVELWHITEFLAG; |
| | 1512 | | if ((levelCurrent > levelPrev) && (visibleChars > 0)) |
| | 1513 | | lev |= SC_FOLDLEVELHEADERFLAG; |
354 | | styler.SetLevel(lineCurrent, lev); | | 1514 | | styler.SetLevel(lineCurrent, lev|SC_FOLDLEVELBASE); |
|
356 | | } | | 1516 | | levelPrev = levelCurrent; |
357 | | } | | 1517 | | visibleChars = 0; |
| | 1518 | | buffer_ends_with_eol = true; |
| | 1519 | | } else if (!isspacechar(ch)) { |
| | 1520 | | visibleChars++; |
| | 1521 | | buffer_ends_with_eol = false; |
| | 1522 | | } |
| | 1523 | | } |
| | 1524 | | // Fill in the real level of the next line, keeping the current flags as they will be filled in later |
| | 1525 | | if (!buffer_ends_with_eol) { |
| | 1526 | | lineCurrent++; |
| | 1527 | | int new_lev = levelCurrent; |
| | 1528 | | if (visibleChars == 0 && foldCompact) |
| | 1529 | | new_lev |= SC_FOLDLEVELWHITEFLAG; |
| | 1530 | | if ((levelCurrent > levelPrev) && (visibleChars > 0)) |
| | 1531 | | new_lev |= SC_FOLDLEVELHEADERFLAG; |
| | 1532 | | levelCurrent = new_lev; |
| | 1533 | | } |
| | 1534 | | styler.SetLevel(lineCurrent, levelCurrent|SC_FOLDLEVELBASE); |
|
|
360 | | 1537 | | static const char * const rubyWordListDesc[] = { |
|
6 skipped lines |