📄 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 + -