//========================================================================================= public StateParserState GetNextState(Token token) { foreach (var oEntry in this.Entries) { if (string.Compare(oEntry.Key, token.TokenTypeName, true) == 0) return oEntry.Value; } return this.ElseState; }
//========================================================================================= internal override TextStyle GetStyleFor(Token token, string styleName) { if (token.TokenTypeName == "comment-start") return this.GetStyleByName("separator"); if (token.TokenTypeName == "comment-end") return this.GetStyleByName("separator"); if (token.TokenTypeName == "attrValue-start") return this.NormalTextStyle; if (token.TokenTypeName == "attrValue-end") return this.NormalTextStyle; if (token.TokenTypeName == "cdata-start") return this.GetStyleByName("separator"); if (token.TokenTypeName == "cdata-end") return this.GetStyleByName("separator"); return base.GetStyleFor(token, styleName); }
//========================================================================================= internal override TextStyle GetStyleFor(Token token, string styleName) { if (token.TokenTypeName == "charConst") return this.TextStyles[S_STRINGS]; return base.GetStyleFor(token, styleName); }
//========================================================================================= void AssertTokenRange(Token token, int startLine, int startCol, int startChar, int endLine, int endCol, int endChar) { Assert.That(token.Start.ToString(), Is.EqualTo(string.Format("Ln:{0}, col:{1}, ch:{2}", startLine, startCol, startChar))); Assert.That(token.End.ToString(), Is.EqualTo(string.Format("Ln:{0}, col:{1}, ch:{2}", endLine, endCol, endChar))); }
//========================================================================================= internal virtual TextStyle GetStyleFor(Token token, string styleName) { TextStyle oStyle = this.GetStyleByName(styleName); if (oStyle != null) return oStyle; if (string.IsNullOrEmpty(token.TokenTypeName)) return this.NormalTextStyle; if (token.TokenTypeName == "id") return this.GetKeywordStyle(token.Text); if (token.TokenTypeName == "comment1") return this.GetStyleByName(S_MULTI_COMMENT); if (token.TokenTypeName == "comment2") return this.GetStyleByName(S_SINGLE_COMMENT); if (token.TokenTypeName == "comment3") return this.GetStyleByName(S_SINGLE_COMMENT); if (token.TokenTypeName == "stringConst") return this.GetStyleByName(S_STRINGS); if (token.TokenTypeName == "operator") return this.GetStyleByName(S_OPERATORS); if (token.TokenTypeName == "number") return this.GetStyleByName(S_NUMBERS); return this.NormalTextStyle; }
//========================================================================================= internal void SetSource(string text) { this.Scanner.SetSource(text); this.TokenPool.Clear(); this.CurrentToken = null; }
//========================================================================================= bool ReadNextToken() { this.CurrentToken = this.Scanner.ReadNextToken(); if (this.CurrentToken == null) return false; else return true; }
//========================================================================================= /// <summary>Если токен многострочный, разбиваем его на строки и добавляем в очередь.</summary> private void EnqueueMultilineToken(string text, TextPoint startPoint, TextPoint endPoint) { TextStyle oStyle = null; ///Если текст однострочный if (text.IndexOf('\n') < 0) { var oToken = new Token( this.CurrentToken.TokenTypeName, text, startPoint, endPoint, this.CurrentToken.Style); oToken.Style = this.Settings.GetStyleFor(oToken, this.CurrentState.StyleName); this.TokenPool.Enqueue(oToken); } else { ///Разбиваем текст на строки List<string> lines = TextSplitter.SplitTextToLines(text); ///Первая строка { string sLine = lines[0]; ///Начало токена var startTokenPoint = startPoint; ///Конец токена int iChar = startPoint.Char + sLine.Length; int iCol = iChar; //TODO: если перед нашим токеном были табы, то iCol мы вычисляем неверно. var endTokenPoint = new TextPoint(startTokenPoint.Line, iCol, iChar); ///Создаем токен var oToken = new Token( this.CurrentToken.TokenTypeName, sLine, startPoint, endTokenPoint, this.CurrentToken.Style); ///Выясняем стиль oStyle = this.Settings.GetStyleFor(oToken, this.CurrentState.StyleName); oToken.Style = oStyle; ///Добавляем в очередь this.TokenPool.Enqueue(oToken); } ///Проходим по остальным строкам for (int iLine = 1; iLine < lines.Count; iLine++) { string sLine = lines[iLine]; if (sLine.Length == 0) continue; ///Начало токена var startTokenPoint = new TextPoint(startPoint.Line + iLine, 0, 0); ///Конец токена int iChar = startTokenPoint.Char + sLine.Length; int iCol = TextCaret.GetCol(sLine, iChar, this.Scanner.TabSize); var endTokenPoint = new TextPoint(startTokenPoint.Line, iCol, iChar); ///Создаем токен var oToken = new Token( this.CurrentToken.TokenTypeName, sLine, startTokenPoint, endTokenPoint, this.CurrentToken.Style); ///Выясняем стиль oToken.Style = oStyle; ///Добавляем в очередь this.TokenPool.Enqueue(oToken); } } }
//========================================================================================= /// <summary>Поместить в очередь токены, описывающие текст в ограничителях.</summary> void EnqueueBoundedToken() { ///Входной ограничитель int iStartLen = this.Scanner.StartLimiterLength; TextPoint pointStartBody = new TextPoint( this.CurrentToken.Start.Line, this.CurrentToken.Start.Col + iStartLen, this.CurrentToken.Start.Char + iStartLen); string sText1 = this.CurrentToken.Text.Substring(0, iStartLen); Token oToken1 = new Token( this.CurrentToken.TokenTypeName + "-start", //TODO: Избавиться от постоянного порождения строк sText1, this.CurrentToken.Start, pointStartBody, this.CurrentToken.Style); oToken1.Style = this.Settings.GetStyleFor(oToken1, this.CurrentState.StyleName); this.TokenPool.Enqueue(oToken1); ///Текст между ограничителей int iEndLen = this.Scanner.EndLimiterLength; TextPoint pointEndBody = new TextPoint( this.CurrentToken.End.Line, this.CurrentToken.End.Col - iEndLen, this.CurrentToken.End.Char - iEndLen); string sText2 = this.CurrentToken.Text.Substring(iStartLen, this.CurrentToken.Text.Length - iStartLen - iEndLen); this.EnqueueMultilineToken(sText2, pointStartBody, pointEndBody); ///Концевой ограничитель string sText3 = this.CurrentToken.Text.Substring(this.CurrentToken.Text.Length - iEndLen); Token oToken3 = new Token( this.CurrentToken.TokenTypeName + "-end", sText3, pointEndBody, this.CurrentToken.End, this.CurrentToken.Style); oToken3.Style = this.Settings.GetStyleFor(oToken3, this.CurrentState.StyleName); this.TokenPool.Enqueue(oToken3); this.CurrentToken = oToken1; }
//========================================================================================= /// <summary>Подставляет указанную строку в редактор заместо текущего токена.</summary> void PasteInsteadOfCurrentToken(Token token, string choose) { //Пользователь ввел начало слова if (token != null && token.Text != "." && token.Text != ",") { int iCurrentLineId = this.Viewer.Caret.Line; string sCurrentLine = this.Viewer.Document[iCurrentLineId].Text; string sNewLine = String.Empty; StringBuilder builder = new StringBuilder(); builder.Append(sCurrentLine, 0, token.Start.Char); builder.Append(choose); int sourceIndex = token.End.Char; int count = sCurrentLine.Length - sourceIndex; builder.Append(sCurrentLine, token.End.Char, count); this.Viewer.Document[iCurrentLineId].Text = builder.ToString(); int iNewCaretCol = token.End.Col - token.Text.Length + choose.Length; this.Viewer.Caret.MoveToPos(iCurrentLineId, iNewCaretCol, true); this.Viewer.InitTokens(this.Viewer.Text); this.Viewer.Invalidate(); return; } //Если текст ещё не подставлен и стоят пробелы не являющиеся токенами this.Viewer.PasteText(choose); this.Viewer.Invalidate(); }
//========================================================================================= void GetQuotedToken(List<Token> tokens, BoundedElement group) { int iCol, iChar; TextPoint endPoint; Token oToken; string sLine = this.Lines[this.CurPos.Line]; ///Если указан стиль оформления границ блока, то надо создать отдельный токен для начала блока if (group.BoundStyle != null) { iChar = this.CurPos.Char + group.StartSymbols.Length; iCol = TextCaret.GetCol(sLine, iChar, this._TabSize); endPoint = new TextPoint(this.CurPos.Line, iCol, iChar); oToken = new Token( group.StartSymbols, this.CurPos, endPoint, group.BoundStyle); tokens.Add(oToken); this.CurPos = endPoint; } ///Если не указаны конечные символы блока, то блок длится до конца строки if (group.EndSymbols.Length == 0) { string sWord = sLine.Substring(this.CurPos.Char); iCol = TextCaret.GetLastCol(sLine, this._TabSize); oToken = new Token(sWord, this.CurPos, new TextPoint(this.CurPos.Line, iCol, sLine.Length - 1), group.Style); tokens.Add(oToken); this.CurPos.Line++; this.CurPos.Char = 0; this.CurPos.Col = 0; return; } bool bFirstLine = true; while (true) { int iIndex = this.CurPos.Char; if (bFirstLine) iIndex += group.StartSymbols.Length; if (iIndex >= sLine.Length) iIndex = -1; else iIndex = sLine.IndexOf(group.EndSymbols, iIndex); if (iIndex >= 0) { bool bEnd = true; if (group.Escape != null) { int iEscapeIndex = sLine.IndexOf(group.Escape); if (iEscapeIndex >= 0 && iEscapeIndex <= iIndex && iEscapeIndex + group.Escape.Length > iIndex) bEnd = false; } if (bEnd) { if (group.BoundStyle == null) iIndex += group.EndSymbols.Length; string sText = sLine.Substring(this.CurPos.Char, iIndex - this.CurPos.Char); iCol = TextCaret.GetCol(sLine, iIndex, this._TabSize); endPoint = new TextPoint(this.CurPos.Line, iCol, iIndex); tokens.Add(new Token(sText, this.CurPos, endPoint, group.Style)); this.CurPos = endPoint; break; } } iCol = TextCaret.GetLastCol(sLine, this._TabSize); endPoint = new TextPoint(this.CurPos.Line, iCol, sLine.Length); if (bFirstLine) sLine = sLine.Substring(this.CurPos.Char); tokens.Add(new Token(sLine, this.CurPos, endPoint, group.Style)); this.CurPos.Line++; this.CurPos.Char = 0; this.CurPos.Col = 0; if (this.CurPos.Line >= this.Lines.Count) break; sLine = this.Lines[this.CurPos.Line]; bFirstLine = false; } ///Если указан стиль оформления границ блока, то надо создать отдельный токен для конца блока if (group.BoundStyle != null) { iChar = this.CurPos.Char + group.EndSymbols.Length; sLine = this.Lines[this.CurPos.Line]; iCol = TextCaret.GetCol(sLine, iChar, this._TabSize); endPoint = new TextPoint(this.CurPos.Line, iCol, iChar); oToken = new Token( group.EndSymbols, this.CurPos, endPoint, group.BoundStyle); tokens.Add(oToken); this.CurPos = endPoint; } }
//========================================================================================= internal override TextStyle GetStyleFor(Token token, string styleName) { if (token.TokenTypeName == "id") { if (token.Text.Length > 2) { if (token.Text[0] == '@') { if (token.Text[1] == '@') return this.TextStyles[S_SERVER_VARIABLES]; else return this.TextStyles[S_VARIABLES]; } } } return base.GetStyleFor(token, styleName); }
//========================================================================================= /// <summary>Сформировать новый токен.</summary> Token GetToken(int start, TextPoint pointStart, int end, TextPoint pointEnd) { if (start >= end) return null; ///Определяем тип токена string sTokenType = (this.CurrentState != null) ? this.CurrentState.ResultTokenName : null; ///Указываем ограничители для текущего токена this.StartLimiterLength = this.CurrentState.StartLimiterLength; this.EndLimiterLength = this.CurrentState.EndLimiterLength; this.LastToken = new Token( sTokenType, this._Reader.GetSubstring(start, end - start), pointStart, pointEnd, null); return this.LastToken; }