Пример #1
0
        public void Style(Scintilla scintilla, int startPos, int endPos)
        {
            // 改行コードをWindowsフォーマット(CR+LF)またはUnixフォーマット(LF)から
            // Macフォーマット(CR)にしたときに発生する例外(IndexOutOfRangeException)を回避
            startPos = startPos < 0 ? 0 : startPos;
            endPos = endPos > scintilla.TextLength ? scintilla.TextLength : endPos;

            int lineNumber = scintilla.LineFromPosition(startPos);
            startPos = scintilla.Lines[lineNumber].Position;

            char chBeforePrev = '\0';
            char chPrev = '\0';
            char ch = '\0';
            char chNext = '\0';
            char chAfterNext = '\0';
            int length = 0;
            ParseState state = ParseState.None;

            switch (scintilla.GetStyleAt(startPos - 1)) {
                case HspLexer.StylePreprocessor:
                    state = ParseState.AfterPreprocessor;
                    break;
                case HspLexer.StyleString:
                    state = ParseState.String;
                    break;
                case HspLexer.StyleComment:
                    state = ParseState.Comment;
                    break;
            }

            scintilla.StartStyling(startPos);

            int currentPos = startPos;
            int currentLine = lineNumber;
            int currentLineStartPos = startPos;
            int currentLineEndPos = scintilla.Lines[lineNumber].EndPosition;

            while (currentPos < endPos) {
                chBeforePrev = (char)scintilla.GetCharAt(currentPos - 2);
                chPrev = (char)scintilla.GetCharAt(currentPos - 1);
                ch = (char)scintilla.GetCharAt(currentPos);
                chNext = (char)scintilla.GetCharAt(currentPos + 1);
                chAfterNext = (char)scintilla.GetCharAt(currentPos + 2);

            Process:
                switch (state) {
                    case ParseState.None:
                        if (ch == '\"') {
                            // 文字列
                            scintilla.SetStyling(1, HspLexer.StyleStringLine);
                            state = ParseState.StringLine;
                        } else if (ch == '{' && chNext == '\"') {
                            // 複数行文字列
                            scintilla.SetStyling(2, HspLexer.StyleString);
                            state = ParseState.String;
                            ++currentPos;
                        } else if (ch == '\'') {
                            // 文字
                            scintilla.SetStyling(1, HspLexer.StyleCharacter);
                            state = ParseState.Character;
                        } else if (ch == ';') {
                            // 単一行コメント
                            scintilla.SetStyling(1, HspLexer.StyleCommentLine);
                            state = ParseState.CommentLine;
                        } else if (ch == '/' && chNext == '/') {
                            // 単一行コメント
                            scintilla.SetStyling(2, HspLexer.StyleCommentLine);
                            state = ParseState.CommentLine;
                            ++currentPos;
                        } else if (ch == '/' && chNext == '*') {
                            // 複数行コメント
                            scintilla.SetStyling(2, HspLexer.StyleComment);
                            state = ParseState.Comment;
                            ++currentPos;
                        } else if (ch == '*' && (Char.IsLetter(chNext) || chNext == '_') &&
                            String.IsNullOrWhiteSpace(scintilla.GetTextRange(
                                currentLineStartPos, currentPos - currentLineStartPos))) {
                            // ラベル
                            scintilla.SetStyling(2, HspLexer.StyleLabel);
                            state = ParseState.Label;
                            ++currentPos;
                        } else if (ch == '#' && length == 0 &&
                            String.IsNullOrWhiteSpace(scintilla.GetTextRange(
                                currentLineStartPos, currentPos - currentLineStartPos))) {
                            // プリプロセッサ
                            state = ParseState.Preprocessor;
                            goto Process;
                        } else if ((Char.IsLetter(ch) || ch == '_') && length == 0) {
                            // 識別子
                            state = ParseState.Identifier;
                            goto Process;
                        } else if (ch == ':') {
                            // 行区切り
                            currentLineStartPos = currentPos + 1;
                            scintilla.SetStyling(1, HspLexer.StyleDefault);
                        } else if (ch == '\0') {
                            // NULL文字の場合はすぐreturn
                            return;
                        } else {
                            scintilla.SetStyling(1, HspLexer.StyleDefault);
                        }
                        break;

                    case ParseState.StringLine:
                        if (ch == '\\' && chNext == '\\') {
                            // エスケープシーケンス '\\'
                            scintilla.SetStyling(2, HspLexer.StyleStringLine);
                            ++currentPos;
                        } else if (ch == '\\' && chNext == '\"') {
                            // エスケープシーケンス '\"'
                            scintilla.SetStyling(2, HspLexer.StyleStringLine);
                            ++currentPos;
                        } else if (ch == '\"') {
                            scintilla.SetStyling(1, HspLexer.StyleStringLine);
                            state = ParseState.None;
                        } else {
                            scintilla.SetStyling(1, HspLexer.StyleStringLine);
                        }
                        break;

                    case ParseState.String:
                        if (ch == '\\' && chNext == '\\') {
                            // エスケープシーケンス '\\'
                            scintilla.SetStyling(2, HspLexer.StyleString);
                            ++currentPos;
                        } else if (ch == '\\' && chNext == '\"') {
                            // エスケープシーケンス '\"'
                            scintilla.SetStyling(2, HspLexer.StyleString);
                            ++currentPos;
                        } else if (ch == '\"' && chNext == '}') {
                            scintilla.SetStyling(2, HspLexer.StyleString);
                            state = ParseState.None;
                            ++currentPos;
                        } else {
                            scintilla.SetStyling(1, HspLexer.StyleString);
                        }
                        break;

                    case ParseState.Character:
                        if (ch == '\'') {
                            scintilla.SetStyling(1, HspLexer.StyleCharacter);
                            state = ParseState.None;
                        } else {
                            scintilla.SetStyling(1, HspLexer.StyleCharacter);
                        }
                        break;

                    case ParseState.CommentLine:
                        if (ch == '\n') {
                            scintilla.SetStyling(1, HspLexer.StyleCommentLine);
                            state = ParseState.None;
                        } else {
                            scintilla.SetStyling(1, HspLexer.StyleCommentLine);
                        }
                        break;

                    case ParseState.Comment:
                        if (ch == '*' && chNext == '/') {
                            scintilla.SetStyling(2, HspLexer.StyleComment);
                            state = ParseState.None;
                            ++currentPos;
                        } else {
                            scintilla.SetStyling(1, HspLexer.StyleComment);
                        }
                        break;

                    case ParseState.Label:
                        if (Char.IsLetterOrDigit(ch) || ch == '_') {
                            scintilla.SetStyling(1, HspLexer.StyleLabel);
                        } else {
                            state = ParseState.None;
                            goto Process;
                        }
                        break;

                    case ParseState.Preprocessor:
                        if (ch == '#' && length == 0 &&
                            String.IsNullOrWhiteSpace(scintilla.GetTextRange(
                                currentLineStartPos, currentPos - currentLineStartPos))) {
                            ++length;
                        } else if ((ch == '\t' || ch == '\u0020' || ch == '\u3000') && length == 1) {
                            // '#' の後のタブ文字, 半角スペース, 全角スペースの場合
                            state = ParseState.SpaceInPreprocessor;
                            goto Process;
                        } else if ((Char.IsLetter(ch) || ch == '_') && length == 1) {
                            ++length;
                        } else if ((Char.IsLetterOrDigit(ch) || ch == '_') && length > 1) {
                            ++length;
                        } else {
                            int style = HspLexer.StyleDefault;
                            string identifier = scintilla.GetTextRange(currentPos - length, length);

                            char[] removeChars = { '\t', '\u0020', '\u3000' };
                            identifier = removeChars.Aggregate(identifier, (s, c) => s.Replace(c.ToString(), String.Empty));
                            identifier = identifier.ToLower();

                            if (this.mKeywords.ContainsKey(identifier)) {
                                switch (this.mKeywords[identifier].mType) {
                                    case KeywordType.Preprocessor:
                                        style = HspLexer.StylePreprocessor;
                                        break;
                                }
                            }

                            scintilla.SetStyling(length, style);
                            length = 0;

                            switch (style) {
                                case HspLexer.StyleDefault:
                                    state = ParseState.None;
                                    break;
                                case HspLexer.StylePreprocessor:
                                    state = ParseState.AfterPreprocessor;
                                    break;
                            }
                            goto Process;
                        }
                        break;

                    case ParseState.SpaceInPreprocessor:
                        if ((ch == '\t' || ch == '\u0020' || ch == '\u3000')) {
                            ++length;
                        } else if ((Char.IsLetter(ch) || ch == '_')) {
                            state = ParseState.Preprocessor;
                            goto Process;
                        } else {
                            scintilla.SetStyling(length, HspLexer.StyleDefault);
                            length = 0;
                            state = ParseState.None;
                            goto Process;
                        }
                        break;

                    case ParseState.AfterPreprocessor:
                        if (ch == '\\' && chNext == '\r' && chAfterNext == '\n') {
                            scintilla.SetStyling(3, HspLexer.StylePreprocessor);
                            currentPos += 2;
                        } else if (ch == '\\' && chNext == '\n') {
                            scintilla.SetStyling(2, HspLexer.StylePreprocessor);
                            ++currentPos;
                        } else if (ch == '\r' && chNext == '\n') {
                            scintilla.SetStyling(2, HspLexer.StyleDefault);
                            state = ParseState.None;
                            ++currentPos;
                        } else if (ch == '\n') {
                            scintilla.SetStyling(1, HspLexer.StyleDefault);
                            state = ParseState.None;
                        } else {
                            scintilla.SetStyling(1, HspLexer.StylePreprocessor);
                        }
                        break;

                    case ParseState.Identifier:
                        if (Char.IsLetterOrDigit(ch) || ch == '_') {
                            ++length;
                        } else {
                            int style = HspLexer.StyleDefault;
                            string identifier = scintilla.GetTextRange(currentPos - length, length);
                            identifier = identifier.ToLower();

                            if (this.mKeywords.ContainsKey(identifier)) {
                                switch (this.mKeywords[identifier].mType) {
                                    case KeywordType.Macro:
                                        style = HspLexer.StyleMacro;
                                        break;
                                    case KeywordType.Function:
                                        style = HspLexer.StyleFunction;
                                        break;
                                    case KeywordType.Type:
                                        style = HspLexer.StyleType;
                                        break;
                                }
                            }

                            scintilla.SetStyling(length, style);
                            length = 0;
                            state = ParseState.None;
                            goto Process;
                        }
                        break;
                }

                ++currentPos;
                currentLine = scintilla.LineFromPosition(currentPos);

                if (currentLineStartPos < scintilla.Lines[currentLine].Position) {
                    currentLineStartPos = scintilla.Lines[currentLine].Position;
                }

                currentLineEndPos = scintilla.Lines[currentLine].EndPosition;
            }
        }