📄 lexruby.cxx
字号:
// We don't have all the heuristics Perl has for indications // of a here-doc, because '<<' is overloadable and used // for so many other classes. } else { state = SCE_RB_HERE_DELIM; HereDoc.State = 0; } } preferRE = (state != SCE_RB_HERE_DELIM); } else if (ch == ':') { styler.ColourTo(i - 1, state); if (chNext == ':') { // Mark "::" as an operator, not symbol start styler.ColourTo(i + 1, SCE_RB_OPERATOR); advance_char(i, ch, chNext, chNext2); // pass by ref state = SCE_RB_DEFAULT; preferRE = false; } else if (isSafeWordcharOrHigh(chNext)) { state = SCE_RB_SYMBOL; } else if (strchr("[*!~+-*/%=<>&^|", chNext)) { // Do the operator analysis in-line, looking ahead // Based on the table in pickaxe 2nd ed., page 339 bool doColoring = true; switch (chNext) { case '[': if (chNext2 == ']' ) { char ch_tmp = styler.SafeGetCharAt(i + 3); if (ch_tmp == '=') { i += 3; ch = ch_tmp; chNext = styler.SafeGetCharAt(i + 1); } else { i += 2; ch = chNext2; chNext = ch_tmp; } } else { doColoring = false; } break; case '*': if (chNext2 == '*') { i += 2; ch = chNext2; chNext = styler.SafeGetCharAt(i + 1); } else { advance_char(i, ch, chNext, chNext2); } break; case '!': if (chNext2 == '=' || chNext2 == '~') { i += 2; ch = chNext2; chNext = styler.SafeGetCharAt(i + 1); } else { advance_char(i, ch, chNext, chNext2); } break; case '<': if (chNext2 == '<') { i += 2; ch = chNext2; chNext = styler.SafeGetCharAt(i + 1); } else if (chNext2 == '=') { char ch_tmp = styler.SafeGetCharAt(i + 3); if (ch_tmp == '>') { // <=> operator i += 3; ch = ch_tmp; chNext = styler.SafeGetCharAt(i + 1); } else { i += 2; ch = chNext2; chNext = ch_tmp; } } else { advance_char(i, ch, chNext, chNext2); } break; default: // Simple one-character operators advance_char(i, ch, chNext, chNext2); break; } if (doColoring) { styler.ColourTo(i, SCE_RB_SYMBOL); state = SCE_RB_DEFAULT; } } else if (!preferRE) { // Don't color symbol strings (yet) // Just color the ":" and color rest as string styler.ColourTo(i, SCE_RB_SYMBOL); state = SCE_RB_DEFAULT; } else { styler.ColourTo(i, SCE_RB_OPERATOR); state = SCE_RB_DEFAULT; preferRE = true; } } else if (ch == '%') { styler.ColourTo(i - 1, state); bool have_string = false; if (strchr(q_chars, chNext) && !isSafeWordcharOrHigh(chNext2)) { Quote.New(); const char *hit = strchr(q_chars, chNext); if (hit != NULL) { state = q_states[hit - q_chars]; Quote.Open(chNext2); i += 2; ch = chNext2; chNext = styler.SafeGetCharAt(i + 1); have_string = true; } } else if (!isSafeWordcharOrHigh(chNext)) { // Ruby doesn't allow high bit chars here, // but the editor host might state = SCE_RB_STRING_QQ; Quote.Open(chNext); advance_char(i, ch, chNext, chNext2); // pass by ref have_string = true; } if (!have_string) { styler.ColourTo(i, SCE_RB_OPERATOR); // stay in default preferRE = true; } } else if (isoperator(ch) || ch == '.') { styler.ColourTo(i - 1, state); styler.ColourTo(i, SCE_RB_OPERATOR); // If we're ending an expression or block, // assume it ends an object, and the ambivalent // constructs are binary operators // // So if we don't have one of these chars, // we aren't ending an object exp'n, and ops // like : << / are unary operators. preferRE = (strchr(")}].", ch) == NULL); // Stay in default state } else if (isEOLChar(ch)) { // Make sure it's a true line-end, with no backslash if ((ch == '\r' || (ch == '\n' && chPrev != '\r')) && chPrev != '\\') { // Assume we've hit the end of the statement. preferRE = true; } } } else if (state == SCE_RB_WORD) { if (ch == '.' || !isSafeWordcharOrHigh(ch)) { // Words include x? in all contexts, // and <letters>= after either 'def' or a dot // Move along until a complete word is on our left // Default accessor treats '.' as word-chars, // but we don't for now. if (ch == '=' && isSafeWordcharOrHigh(chPrev) && (chNext == '(' || strchr(" \t\n\r", chNext) != NULL) && (!strcmp(prevWord, "def") || followsDot(styler.GetStartSegment(), styler))) { // <name>= is a name only when being def'd -- Get it the next time // This means that <name>=<name> is always lexed as // <name>, (op, =), <name> } else if ((ch == '?' || ch == '!') && isSafeWordcharOrHigh(chPrev) && !isSafeWordcharOrHigh(chNext)) { // <name>? is a name -- Get it the next time // But <name>?<name> is always lexed as // <name>, (op, ?), <name> // Same with <name>! to indicate a method that // modifies its target } else if (isEOLChar(ch) && isMatch(styler, lengthDoc, i - 7, "__END__")) { styler.ColourTo(i, SCE_RB_DATASECTION); state = SCE_RB_DATASECTION; // No need to handle this state -- we'll just move to the end preferRE = false; } else { int wordStartPos = styler.GetStartSegment(); int word_style = ClassifyWordRb(wordStartPos, i - 1, keywords, styler, prevWord); switch (word_style) { case SCE_RB_WORD: preferRE = RE_CanFollowKeyword(prevWord); break; case SCE_RB_WORD_DEMOTED: preferRE = true; break; case SCE_RB_IDENTIFIER: if (isMatch(styler, lengthDoc, wordStartPos, "print")) { preferRE = true; } else if (isEOLChar(ch)) { preferRE = true; } else { preferRE = false; } break; default: preferRE = false; } if (ch == '.') { // We might be redefining an operator-method preferRE = false; } // And if it's the first redo_char(i, ch, chNext, chNext2, state); // pass by ref } } } else if (state == SCE_RB_NUMBER) { if (isSafeAlnumOrHigh(ch) || ch == '_') { // Keep going } else if (ch == '.' && ++numDots == 1) { // Keep going } else { styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); // pass by ref preferRE = false; } } else if (state == SCE_RB_COMMENTLINE) { if (isEOLChar(ch)) { styler.ColourTo(i - 1, state); state = SCE_RB_DEFAULT; // Use whatever setting we had going into the comment } } else if (state == SCE_RB_HERE_DELIM) { // See the comment for SCE_RB_HERE_DELIM in LexPerl.cxx // Slightly different: if we find an immediate '-', // the target can appear indented. if (HereDoc.State == 0) { // '<<' encountered HereDoc.State = 1; HereDoc.DelimiterLength = 0; if (ch == '-') { HereDoc.CanBeIndented = true; advance_char(i, ch, chNext, chNext2); // pass by ref } else { HereDoc.CanBeIndented = false; } if (isEOLChar(ch)) { // Bail out of doing a here doc if there's no target state = SCE_RB_DEFAULT; preferRE = false; } else { HereDoc.Quote = ch; if (ch == '\'' || ch == '"' || ch == '`') { HereDoc.Quoted = true; HereDoc.Delimiter[0] = '\0'; } else { HereDoc.Quoted = false; HereDoc.Delimiter[0] = ch; HereDoc.Delimiter[1] = '\0'; HereDoc.DelimiterLength = 1; } } } else if (HereDoc.State == 1) { // collect the delimiter if (isEOLChar(ch)) { // End the quote now, and go back for more styler.ColourTo(i - 1, state); state = SCE_RB_DEFAULT; i--; chNext = ch; chNext2 = chNext; preferRE = false; } else if (HereDoc.Quoted) { if (ch == HereDoc.Quote) { // closing quote => end of delimiter styler.ColourTo(i, state); state = SCE_RB_DEFAULT; preferRE = false; } else { if (ch == '\\' && !isEOLChar(chNext)) { advance_char(i, ch, chNext, chNext2); } HereDoc.Delimiter[HereDoc.DelimiterLength++] = ch; HereDoc.Delimiter[HereDoc.DelimiterLength] = '\0'; } } else { // an unquoted here-doc delimiter if (isSafeAlnumOrHigh(ch) || ch == '_') { HereDoc.Delimiter[HereDoc.DelimiterLength++] = ch; HereDoc.Delimiter[HereDoc.DelimiterLength] = '\0'; } else { styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); preferRE = false; } } if (HereDoc.DelimiterLength >= static_cast<int>(sizeof(HereDoc.Delimiter)) - 1) { styler.ColourTo(i - 1, state); state = SCE_RB_ERROR; preferRE = false; } } } else if (state == SCE_RB_HERE_Q) { // Not needed: HereDoc.State == 2 // Indentable here docs: look backwards // Non-indentable: look forwards, like in Perl // // Why: so we can quickly resolve things like <<-" abc" if (!HereDoc.CanBeIndented) { if (isEOLChar(chPrev) && isMatch(styler, lengthDoc, i, HereDoc.Delimiter)) { styler.ColourTo(i - 1, state); i += HereDoc.DelimiterLength - 1; chNext = styler.SafeGetCharAt(i + 1); if (isEOLChar(chNext)) { styler.ColourTo(i, SCE_RB_HERE_DELIM); state = SCE_RB_DEFAULT; HereDoc.State = 0; preferRE = false; } // Otherwise we skipped through the here doc faster. } } else if (isEOLChar(chNext) && lookingAtHereDocDelim(styler, i - HereDoc.DelimiterLength + 1, lengthDoc, HereDoc.Delimiter)) { styler.ColourTo(i - 1 - HereDoc.DelimiterLength, state); styler.ColourTo(i, SCE_RB_HERE_DELIM); state = SCE_RB_DEFAULT; preferRE = false; HereDoc.State = 0; } } else if (state == SCE_RB_CLASS_VAR || state == SCE_RB_INSTANCE_VAR || state == SCE_RB_SYMBOL) { if (!isSafeWordcharOrHigh(ch)) { styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); // pass by ref preferRE = false; } } else if (state == SCE_RB_GLOBAL) { if (!isSafeWordcharOrHigh(ch)) { // handle special globals here as well if (chPrev == '$') { if (ch == '-') { // Include the next char, like $-a advance_char(i, ch, chNext, chNext2); } styler.ColourTo(i, state); state = SCE_RB_DEFAULT; } else { styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); // pass by ref } preferRE = false; } } else if (state == SCE_RB_POD) { // PODs end with ^=end\s, -- any whitespace can follow =end if (strchr(" \t\n\r", ch) != NULL && i > 5 && isEOLChar(styler[i - 5]) && isMatch(styler, lengthDoc, i - 4, "=end")) { styler.ColourTo(i - 1, state); state = SCE_RB_DEFAULT; preferRE = false; } } else if (state == SCE_RB_REGEX || state == SCE_RB_STRING_QR) { if (ch == '\\' && Quote.Up != '\\') { // Skip one advance_char(i, ch, chNext, chNext2); } else if (ch == Quote.Down) { Quote.Count--; if (Quote.Count == 0) { // Include the options while (isSafeAlpha(chNext)) { i++; ch = chNext; chNext = styler.SafeGetCharAt(i + 1); } styler.ColourTo(i, state); state = SCE_RB_DEFAULT; preferRE = false; } } else if (ch == Quote.Up) { // Only if close quoter != open quoter Quote.Count++; } else if (ch == '#' ) { //todo: distinguish comments from pound chars
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -