⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lexruby.cxx

📁 Wxpython Implemented on Windows CE, Source code
💻 CXX
📖 第 1 页 / 共 4 页
字号:
                // for now, handle as comment
                styler.ColourTo(i - 1, state);
                bool inEscape = false;
                while (++i < lengthDoc) {
                    ch = styler.SafeGetCharAt(i);
                    if (ch == '\\') {
                        inEscape = true;
                    } else if (isEOLChar(ch)) {
                        // Comment inside a regex
                        styler.ColourTo(i - 1, SCE_RB_COMMENTLINE);
                        break;
                    } else if (inEscape) {
                        inEscape = false;  // don't look at char
                    } else if (ch == Quote.Down) {
                        // Have the regular handler deal with this
                        // to get trailing modifiers.
                        i--;
                        ch = styler[i];
						break;
                    }
                }
                chNext = styler.SafeGetCharAt(i + 1);
                chNext2 = styler.SafeGetCharAt(i + 2);
            }
        // Quotes of all kinds...
        } else if (state == SCE_RB_STRING_Q || state == SCE_RB_STRING_QQ || 
                   state == SCE_RB_STRING_QX || state == SCE_RB_STRING_QW ||
                   state == SCE_RB_STRING || state == SCE_RB_CHARACTER ||
                   state == SCE_RB_BACKTICKS) {
            if (!Quote.Down && !isspacechar(ch)) {
                Quote.Open(ch);
            } else if (ch == '\\' && Quote.Up != '\\') {
                //Riddle me this: Is it safe to skip *every* escaped char?
                advance_char(i, ch, chNext, chNext2);
            } else if (ch == Quote.Down) {
                Quote.Count--;
                if (Quote.Count == 0) {
                    styler.ColourTo(i, state);
                    state = SCE_RB_DEFAULT;
                    preferRE = false;
                }
            } else if (ch == Quote.Up) {
                Quote.Count++;
            }
        }
            
        if (state == SCE_RB_ERROR) {
            break;
        }
        chPrev = ch;
    }
    if (state == SCE_RB_WORD) {
        // We've ended on a word, possibly at EOF, and need to
        // classify it.
        (void) ClassifyWordRb(styler.GetStartSegment(), lengthDoc - 1, keywords, styler, prevWord);
    } else {
        styler.ColourTo(lengthDoc - 1, state);
    }
}

// Helper functions for folding, disambiguation keywords
// Assert that there are no high-bit chars 

static void getPrevWord(int pos,
                        char *prevWord,
                        Accessor &styler,
                        int word_state)
{
    int i;
    styler.Flush();
    for (i = pos - 1; i > 0; i--) {
        if (actual_style(styler.StyleAt(i)) != word_state) {
            i++;
            break;
        }
    }
    if (i < pos - MAX_KEYWORD_LENGTH) // overflow
        i = pos - MAX_KEYWORD_LENGTH;
    char *dst = prevWord;
    for (; i <= pos; i++) {
        *dst++ = styler[i];
    }
	*dst = 0;
}

static bool keywordIsAmbiguous(const char *prevWord)
{
    // Order from most likely used to least likely
    // Lots of ways to do a loop in Ruby besides 'while/until'
    if (!strcmp(prevWord, "if")
        || !strcmp(prevWord, "do")
        || !strcmp(prevWord, "while")
        || !strcmp(prevWord, "unless")
        || !strcmp(prevWord, "until")) {
        return true;
    } else {
        return false;
    }
}

// Demote keywords in the following conditions:
// if, while, unless, until modify a statement
// do after a while or until, as a noise word (like then after if) 

static bool keywordIsModifier(const char *word,
                              int pos,
                              Accessor &styler)
{
    if (word[0] == 'd' && word[1] == 'o' && !word[2]) {
        return keywordDoStartsLoop(pos, styler);
    }
    char ch;
    int style = SCE_RB_DEFAULT;
	int lineStart = styler.GetLine(pos);
    int lineStartPosn = styler.LineStart(lineStart);
    styler.Flush();
    while (--pos >= lineStartPosn) {
        style = actual_style(styler.StyleAt(pos));
		if (style == SCE_RB_DEFAULT) {
			if (iswhitespace(ch = styler[pos])) {
				//continue
			} else if (ch == '\r' || ch == '\n') {
				// Scintilla's LineStart() and GetLine() routines aren't
				// platform-independent, so if we have text prepared with
				// a different system we can't rely on it.
				return false;
			}
		} else {
            break;
		}
    }
    if (pos < lineStartPosn) {
        return false; //XXX not quite right if the prev line is a continuation
    }
    // First things where the action is unambiguous
    switch (style) {
        case SCE_RB_DEFAULT:
        case SCE_RB_COMMENTLINE:
        case SCE_RB_POD:
        case SCE_RB_CLASSNAME:
        case SCE_RB_DEFNAME:
        case SCE_RB_MODULE_NAME:
            return false;
        case SCE_RB_OPERATOR:
            break;
        case SCE_RB_WORD:
            // Watch out for uses of 'else if'
            //XXX: Make a list of other keywords where 'if' isn't a modifier
            //     and can appear legitimately
            // Formulate this to avoid warnings from most compilers
            if (strcmp(word, "if") == 0) {
                char prevWord[MAX_KEYWORD_LENGTH + 1];
                getPrevWord(pos, prevWord, styler, SCE_RB_WORD);
                return strcmp(prevWord, "else") != 0;
            }
            return true;
        default:
            return true;
    }
    // Assume that if the keyword follows an operator,
    // usually it's a block assignment, like
    // a << if x then y else z
    
    ch = styler[pos];
    switch (ch) {
        case ')':
        case ']':
        case '}':
            return true;
        default:
            return false;
    }
}

#define WHILE_BACKWARDS "elihw"
#define UNTIL_BACKWARDS "litnu"

// Nothing fancy -- look to see if we follow a while/until somewhere
// on the current line

static bool keywordDoStartsLoop(int pos,
                                Accessor &styler)
{
    char ch;
    int style;
	int lineStart = styler.GetLine(pos);
    int lineStartPosn = styler.LineStart(lineStart);
    styler.Flush();
    while (--pos >= lineStartPosn) {
        style = actual_style(styler.StyleAt(pos));
		if (style == SCE_RB_DEFAULT) {
			if ((ch = styler[pos]) == '\r' || ch == '\n') {
				// Scintilla's LineStart() and GetLine() routines aren't
				// platform-independent, so if we have text prepared with
				// a different system we can't rely on it.
				return false;
			}
		} else if (style == SCE_RB_WORD) {
            // Check for while or until, but write the word in backwards
            char prevWord[MAX_KEYWORD_LENGTH + 1]; // 1 byte for zero
            char *dst = prevWord;
            int wordLen = 0;
            int start_word;
            for (start_word = pos;
                 start_word >= lineStartPosn && actual_style(styler.StyleAt(start_word)) == SCE_RB_WORD;
                 start_word--) {
                if (++wordLen < MAX_KEYWORD_LENGTH) {
                    *dst++ = styler[start_word];
                }
            }
            *dst = 0;
            // Did we see our keyword?
            if (!strcmp(prevWord, WHILE_BACKWARDS)
                || !strcmp(prevWord, UNTIL_BACKWARDS)) {
                return true;
            }
            // We can move pos to the beginning of the keyword, and then
            // accept another decrement, as we can never have two contiguous
            // keywords:
            // word1 word2
            //           ^
            //        <-  move to start_word
            //      ^
            //      <- loop decrement
            //     ^  # pointing to end of word1 is fine
            pos = start_word;
        }
    }
    return false;
}

/*
 *  Folding Ruby
 * 
 *  The language is quite complex to analyze without a full parse.
 *  For example, this line shouldn't affect fold level:
 * 
 *   print "hello" if feeling_friendly?
 * 
 *  Neither should this:
 * 
 *   print "hello" \
 *      if feeling_friendly?
 * 
 * 
 *  But this should:
 * 
 *   if feeling_friendly?  #++
 *     print "hello" \
 *     print "goodbye"
 *   end                   #--
 * 
 *  So we cheat, by actually looking at the existing indentation
 *  levels for each line, and just echoing it back.  Like Python.
 *  Then if we get better at it, we'll take braces into consideration,
 *  which always affect folding levels.

 *  How the keywords should work:
 *  No effect:
 *  __FILE__ __LINE__ BEGIN END alias and 
 *  defined? false in nil not or self super then
 *  true undef

 *  Always increment:
 *  begin  class def do for module when {
 * 
 *  Always decrement:
 *  end }
 * 
 *  Increment if these start a statement
 *  if unless until while -- do nothing if they're modifiers

 *  These end a block if there's no modifier, but don't bother
 *  break next redo retry return yield
 * 
 *  These temporarily de-indent, but re-indent
 *  case else elsif ensure rescue
 * 
 *  This means that the folder reflects indentation rather
 *  than setting it.  The language-service updates indentation
 *  when users type return and finishes entering de-denters.
 * 
 *  Later offer to fold POD, here-docs, strings, and blocks of comments
 */

static void FoldRbDoc(unsigned int startPos, int length, int initStyle,
                      WordList *[], Accessor &styler) {
	const bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
    
    synchronizeDocStart(startPos, length, initStyle, styler, // ref args
                        false);
	unsigned int endPos = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = startPos == 0 ? 0 : (styler.LevelAt(lineCurrent)
                                         & SC_FOLDLEVELNUMBERMASK
                                         & ~SC_FOLDLEVELBASE);
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int styleNext = styler.StyleAt(startPos);
	int stylePrev = startPos <= 1 ? SCE_RB_DEFAULT : styler.StyleAt(startPos - 1);
    bool buffer_ends_with_eol = false;
	for (unsigned int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
        if (style == SCE_RB_COMMENTLINE) {
            if (foldComment && stylePrev != SCE_RB_COMMENTLINE) {
                if (chNext == '{') {
					levelCurrent++;
				} else if (chNext == '}') {
					levelCurrent--;
				}
            }
        } else if (style == SCE_RB_OPERATOR) {
			if (strchr("[{(", ch)) {
				levelCurrent++;
			} else if (strchr(")}]", ch)) {
                // Don't decrement below 0
                if (levelCurrent > 0)
                    levelCurrent--;
			}
        } else if (style == SCE_RB_WORD && styleNext != SCE_RB_WORD) {
            // Look at the keyword on the left and decide what to do
            char prevWord[MAX_KEYWORD_LENGTH + 1]; // 1 byte for zero
            prevWord[0] = 0;
            getPrevWord(i, prevWord, styler, SCE_RB_WORD);
            if (!strcmp(prevWord, "end")) {
                // Don't decrement below 0
                if (levelCurrent > 0)
                    levelCurrent--;
            } else if (   !strcmp(prevWord, "if")
                       || !strcmp(prevWord, "def")
                       || !strcmp(prevWord, "class")
                       || !strcmp(prevWord, "module")
                       || !strcmp(prevWord, "begin")
                       || !strcmp(prevWord, "case")
                       || !strcmp(prevWord, "do")
                       || !strcmp(prevWord, "while")
                       || !strcmp(prevWord, "unless")
                       || !strcmp(prevWord, "until")
                       || !strcmp(prevWord, "for")
                          ) {
				levelCurrent++;
            }
        }
		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
            styler.SetLevel(lineCurrent, lev|SC_FOLDLEVELBASE);
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
            buffer_ends_with_eol = true;
		} else if (!isspacechar(ch)) {
			visibleChars++;
            buffer_ends_with_eol = false;
        }
    }
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
    if (!buffer_ends_with_eol) {
        lineCurrent++;
        int new_lev = levelCurrent;
        if (visibleChars == 0 && foldCompact)
            new_lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				new_lev |= SC_FOLDLEVELHEADERFLAG;
            levelCurrent = new_lev;
    }
	styler.SetLevel(lineCurrent, levelCurrent|SC_FOLDLEVELBASE);
}

static const char * const rubyWordListDesc[] = {
	"Keywords",
	0
};

LexerModule lmRuby(SCLEX_RUBY, ColouriseRbDoc, "ruby", FoldRbDoc, rubyWordListDesc);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -