📄 lexperl.cxx
字号:
state = SCE_PL_REGSUBST; Quote.New(2); } else if (ch == 'm' && !isNonQuote(chNext)) { state = SCE_PL_REGEX; Quote.New(1); } else if (ch == 'q' && !isNonQuote(chNext)) { state = SCE_PL_STRING_Q; Quote.New(1); } else if (ch == 'y' && !isNonQuote(chNext)) { state = SCE_PL_REGSUBST; Quote.New(2); } else if (ch == 't' && chNext == 'r' && !isNonQuote(chNext2)) { state = SCE_PL_REGSUBST; Quote.New(2); kw++; } else if (ch == 'q' && (chNext == 'q' || chNext == 'r' || chNext == 'w' || chNext == 'x') && !isNonQuote(chNext2)) { if (chNext == 'q') state = SCE_PL_STRING_QQ; else if (chNext == 'x') state = SCE_PL_STRING_QX; else if (chNext == 'r') state = SCE_PL_STRING_QR; else if (chNext == 'w') state = SCE_PL_STRING_QW; Quote.New(1); kw++; } else if (ch == 'x' && (chNext == '=' || // repetition !isWordStart(chNext) || (isdigit(chPrev) && isdigit(chNext)))) { state = SCE_PL_OPERATOR; } // if potentially a keyword, scan forward and grab word, then check // if it's really one; if yes, disambiguation test is performed // otherwise it is always a bareword and we skip a lot of scanning // note: keywords assumed to be limited to [_a-zA-Z] only if (state == SCE_PL_WORD) { while (isWordStart(styler.SafeGetCharAt(kw))) kw++; if (!isPerlKeyword(styler.GetStartSegment(), kw, keywords, styler)) { state = SCE_PL_IDENTIFIER; } } // if already SCE_PL_IDENTIFIER, then no ambiguity, skip this // for quote-like delimiters/keywords, attempt to disambiguate // to select for bareword, change state -> SCE_PL_IDENTIFIER if (state != SCE_PL_IDENTIFIER && i > 0) { unsigned int j = i; bool moreback = false; // true if passed newline/comments bool brace = false; // true if opening brace found char ch2; // first look backwards past whitespace/comments for EOLs // if BACK_NONE, neither operator nor keyword, so skip test if (backflag != BACK_NONE) { while (--j > backPos) { if (isEOLChar(styler.SafeGetCharAt(j))) moreback = true; } ch2 = styler.SafeGetCharAt(j); if (ch2 == '{' && !moreback) { // {bareword: possible variable spec brace = true; } else if ((ch2 == '&' && styler.SafeGetCharAt(j - 1) != '&') // &bareword: subroutine call || (ch2 == '>' && styler.SafeGetCharAt(j - 1) == '-') // ->bareword: part of variable spec || (ch2 == 'b' && styler.Match(j - 2, "su"))) { // sub bareword: subroutine declaration // (implied BACK_KEYWORD, no keywords end in 'sub'!) state = SCE_PL_IDENTIFIER; } // if status still ambiguous, look forward after word past // tabs/spaces only; if ch2 isn't one of '[{(,' it can never // match anything, so skip the whole thing j = kw; if (state != SCE_PL_IDENTIFIER && (ch2 == '{' || ch2 == '(' || ch2 == '['|| ch2 == ',') && kw < lengthDoc) { while (ch2 = styler.SafeGetCharAt(j), (ch2 == ' ' || ch2 == '\t') && j < lengthDoc) { j++; } if ((ch2 == '}' && brace) // {bareword}: variable spec || (ch2 == '=' && styler.SafeGetCharAt(j + 1) == '>')) { // [{(, bareword=>: hash literal state = SCE_PL_IDENTIFIER; } } } } backflag = BACK_NONE; // an identifier or bareword if (state == SCE_PL_IDENTIFIER) { if ((!isWordStart(chNext) && chNext != '\'') || (chNext == '.' && chNext2 == '.')) { // We need that if length of word == 1! // This test is copied from the SCE_PL_WORD handler. styler.ColourTo(i, SCE_PL_IDENTIFIER); state = SCE_PL_DEFAULT; } // a keyword } else if (state == SCE_PL_WORD) { i = kw - 1; if (ch == '_' && chNext == '_' && (isMatch(styler, lengthDoc, styler.GetStartSegment(), "__DATA__") || isMatch(styler, lengthDoc, styler.GetStartSegment(), "__END__"))) { styler.ColourTo(i, SCE_PL_DATASECTION); state = SCE_PL_DATASECTION; } else { if (isMatch(styler, lengthDoc, styler.GetStartSegment(), "format")) { state = SCE_PL_FORMAT_IDENT; HereDoc.State = 0; } else { state = SCE_PL_DEFAULT; } styler.ColourTo(i, SCE_PL_WORD); backflag = BACK_KEYWORD; backPos = i; } ch = styler.SafeGetCharAt(i); chNext = styler.SafeGetCharAt(i + 1); // a repetition operator 'x' } else if (state == SCE_PL_OPERATOR) { state = SCE_PL_DEFAULT; goto handleOperator; // quote-like delimiter, skip one char if double-char delimiter } else { i = kw - 1; chNext = styler.SafeGetCharAt(i + 1); } } else if (ch == '#') { state = SCE_PL_COMMENTLINE; } else if (ch == '\"') { state = SCE_PL_STRING; Quote.New(1); Quote.Open(ch); backflag = BACK_NONE; } else if (ch == '\'') { if (chPrev == '&') { // Archaic call styler.ColourTo(i, state); } else { state = SCE_PL_CHARACTER; Quote.New(1); Quote.Open(ch); } backflag = BACK_NONE; } else if (ch == '`') { state = SCE_PL_BACKTICKS; Quote.New(1); Quote.Open(ch); backflag = BACK_NONE; } else if (ch == '$') { if ((chNext == '{') || isspacechar(chNext)) { styler.ColourTo(i, SCE_PL_SCALAR); } else { state = SCE_PL_SCALAR; if ((chNext == '`' && chNext2 == '`') || (chNext == ':' && chNext2 == ':')) { i += 2; ch = styler.SafeGetCharAt(i); chNext = styler.SafeGetCharAt(i + 1); } else { i++; ch = chNext; chNext = chNext2; } } backflag = BACK_NONE; } else if (ch == '@') { if (!isascii(chNext) || isalpha(chNext) || chNext == '#' || chNext == '$' || chNext == '_' || chNext == '+' || chNext == '-') { state = SCE_PL_ARRAY; } else if (chNext == ':' && chNext2 == ':') { state = SCE_PL_ARRAY; i += 2; ch = styler.SafeGetCharAt(i); chNext = styler.SafeGetCharAt(i + 1); } else if (chNext != '{' && chNext != '[') { styler.ColourTo(i, SCE_PL_ARRAY); } else { styler.ColourTo(i, SCE_PL_ARRAY); } backflag = BACK_NONE; } else if (ch == '%') { backflag = BACK_NONE; if (!isascii(chNext) || isalpha(chNext) || chNext == '#' || chNext == '$' || chNext == '_' || chNext == '!' || chNext == '^') { state = SCE_PL_HASH; i++; ch = chNext; chNext = chNext2; } else if (chNext == ':' && chNext2 == ':') { state = SCE_PL_HASH; i += 2; ch = styler.SafeGetCharAt(i); chNext = styler.SafeGetCharAt(i + 1); } else if (chNext == '{') { styler.ColourTo(i, SCE_PL_HASH); } else { goto handleOperator; } } else if (ch == '*') { backflag = BACK_NONE; char strch[2]; strch[0] = chNext; strch[1] = '\0'; if (chNext == ':' && chNext2 == ':') { state = SCE_PL_SYMBOLTABLE; i += 2; ch = styler.SafeGetCharAt(i); chNext = styler.SafeGetCharAt(i + 1); } else if (!isascii(chNext) || isalpha(chNext) || chNext == '_' || NULL != strstr("^/|,\\\";#%^:?<>)[]", strch)) { state = SCE_PL_SYMBOLTABLE; i++; ch = chNext; chNext = chNext2; } else if (chNext == '{') { styler.ColourTo(i, SCE_PL_SYMBOLTABLE); } else { if (chNext == '*') { // exponentiation i++; ch = chNext; chNext = chNext2; } goto handleOperator; } } else if (ch == '/' || (ch == '<' && chNext == '<')) { // Explicit backward peeking to set a consistent preferRE for // any slash found, so no longer need to track preferRE state. // Find first previous significant lexed element and interpret. // Test for HERE doc start '<<' shares this code, helps to // determine if it should be an operator. bool preferRE = false; bool isHereDoc = (ch == '<'); bool hereDocSpace = false; // these are for corner case: bool hereDocScalar = false; // SCALAR [whitespace] '<<' unsigned int bk = (i > 0)? i - 1: 0; unsigned int bkend; char bkch; styler.Flush(); if (styler.StyleAt(bk) == SCE_PL_DEFAULT) hereDocSpace = true; while ((bk > 0) && (styler.StyleAt(bk) == SCE_PL_DEFAULT || styler.StyleAt(bk) == SCE_PL_COMMENTLINE)) { bk--; } if (bk == 0) { // position 0 won't really be checked; rarely happens // hard to fix due to an unsigned index i preferRE = true; } else { int bkstyle = styler.StyleAt(bk); bkch = styler.SafeGetCharAt(bk); switch(bkstyle) { case SCE_PL_OPERATOR: preferRE = true; if (bkch == ')' || bkch == ']') { preferRE = false; } else if (bkch == '}') { // backtrack further, count balanced brace pairs // if a brace pair found, see if it's a variable int braceCount = 1; while (--bk > 0) { bkstyle = styler.StyleAt(bk); if (bkstyle == SCE_PL_OPERATOR) { bkch = styler.SafeGetCharAt(bk); if (bkch == ';') { // early out break; } else if (bkch == '}') { braceCount++; } else if (bkch == '{') { if (--braceCount == 0) break; } } } if (bk == 0) { // at beginning, true } else if (braceCount == 0) { // balanced { found, bk>0, skip more whitespace if (styler.StyleAt(--bk) == SCE_PL_DEFAULT) { while (bk > 0) { bkstyle = styler.StyleAt(--bk); if (bkstyle != SCE_PL_DEFAULT) break; } } bkstyle = styler.StyleAt(bk); if (bkstyle == SCE_PL_SCALAR || bkstyle == SCE_PL_ARRAY || bkstyle == SCE_PL_HASH || bkstyle == SCE_PL_SYMBOLTABLE || bkstyle == SCE_PL_OPERATOR) { preferRE = false; } } } break; case SCE_PL_IDENTIFIER: preferRE = true; if (bkch == '>') { // inputsymbol preferRE = false; break; } // backtrack to find "->" or "::" before identifier while (bk > 0 && styler.StyleAt(bk) == SCE_PL_IDENTIFIER) { bk--; } while (bk > 0) { bkstyle = styler.StyleAt(bk); if (bkstyle == SCE_PL_DEFAULT || bkstyle == SCE_PL_COMMENTLINE) { } else if (bkstyle == SCE_PL_OPERATOR) { bkch = styler.SafeGetCharAt(bk); // test for "->" and "::" if ((bkch == '>' && styler.SafeGetCharAt(bk - 1) == '-') || (bkch == ':' && styler.SafeGetCharAt(bk - 1) == ':')) { preferRE = false; break; } } else { // bare identifier, if '/', /PATTERN/ unless digit/space immediately after '/' // if '//', always expect defined-or operator to follow identifier if (!isHereDoc && (isspacechar(chNext) || isdigit(chNext) || chNext == '/')) preferRE = false; // HERE docs cannot have a space after the >> if (isspacechar(chNext)) preferRE = false; break; } bk--; } break; case SCE_PL_SCALAR: // for $var<< case hereDocScalar = true; break; // for HERE docs, always true for preferRE case SCE_PL_WORD: preferRE = true; if (isHereDoc) break; // adopt heuristics similar to vim-style rules: // keywords always forced as /PATTERN/: split, if, elsif, while // everything else /PATTERN/ unless digit/space immediately after '/' // for '//', defined-or favoured unless special keywords bkend = bk + 1; while (bk > 0 && styler.StyleAt(bk-1) == SCE_PL_WORD) { bk--; } if (isPerlKeyword(bk, bkend, reWords, styler)) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -