private static void Output(ColoredCharacter[] result, ref int index, string value, ConsoleColor color) { for (var i = 0; i < value.Length; i++, index++) { result[index] = new ColoredCharacter(value[i], color); } }
public ColoredCharacter[] Highlight(string line) { var index = 0; var result = new ColoredCharacter[line.Length]; while (index < line.Length) { switch (_state) { case TokenState.None: ColorNone(line, result, ref index); break; case TokenState.MultiComment: ColorMultiComment(line, result, ref index); break; case TokenState.String: ColorString(line, result, ref index); break; } } return(result); }
private void ColorMultiComment(string line, ColoredCharacter[] result, ref int index) { while (_multiCommentDepth > 0) { if (index >= line.Length) { return; } if (OutputIfNext(line, result, ref index, "/*", CommentColor)) { _multiCommentDepth++; continue; } if (OutputIfNext(line, result, ref index, "*/", CommentColor)) { _multiCommentDepth--; continue; } result[index] = new ColoredCharacter(line[index], CommentColor); index++; } _state = TokenState.None; }
private void ColorString(string line, ColoredCharacter[] result, ref int index) { while (index < line.Length) { var ch = line[index]; if (ch == '\\' && index + 1 < line.Length && line[index + 1] == _stringTerminator) { result[index + 0] = new ColoredCharacter('\\', StringColor); result[index + 1] = new ColoredCharacter(_stringTerminator, StringColor); index += 2; continue; } result[index] = new ColoredCharacter(ch, StringColor); index++; if (ch == _stringTerminator) { _state = TokenState.None; _stringTerminator = '\0'; return; } } }
public ColoredCharacter[] Highlight(string line) { var index = 0; var result = new ColoredCharacter[line.Length]; while (index < line.Length) { switch (_state) { case TokenState.None: ColorNone(line, result, ref index); break; case TokenState.MultiComment: ColorMultiComment(line, result, ref index); break; case TokenState.String: ColorString(line, result, ref index); break; } } return result; }
private void ColorNone(string line, ColoredCharacter[] result, ref int index) { while (index < line.Length) { if (OutputIfNext(line, result, ref index, "//", CommentColor)) { for (var i = index; i < line.Length; i++, index++) { result[i] = new ColoredCharacter(line[i], CommentColor); } return; } if (OutputIfNext(line, result, ref index, "/*", CommentColor)) { _state = TokenState.MultiComment; _multiCommentDepth = 1; return; } var ch = line[index]; if (OutputIfNext(line, result, ref index, "\"", StringColor) || OutputIfNext(line, result, ref index, "\'", StringColor)) { _state = TokenState.String; _stringTerminator = ch; return; } if (Operators.TryGetValue(ch, out var operators)) { var idx = index; var op = operators.FirstOrDefault(s => IsNext(line, idx, s)); if (op != null) { Output(result, ref index, op, OperatorColor); continue; } } if (char.IsLetter(ch) || ch == '_' || ch == '`') { var start = index; var isBacktick = ch == '`'; if (isBacktick) { index++; // opening backtick } while (index < line.Length && (char.IsLetterOrDigit(line[index]) || line[index] == '_')) { index++; } if (isBacktick && index < line.Length && line[index] == '`') { index++; // closing backtick } var word = line.Substring(start, index - start); index = start; if (isBacktick) { Output(result, ref index, word, OperatorColor); continue; } if (Keywords.Contains(word)) { Output(result, ref index, word, KeywordColor); continue; } Output(result, ref index, word, IdentifierColor); continue; } if (char.IsDigit(ch)) { var format = NumberFormat.Decimal; var hasDecimal = false; var hasExp = false; var justTake = false; if (ch == '0' && index + 1 < line.Length) { var nextChar = line[index + 1]; if (nextChar == 'x' || nextChar == 'X') { format = NumberFormat.Hexadecimal; } if (nextChar == 'b' || nextChar == 'B') { format = NumberFormat.Binary; } if (format != NumberFormat.Decimal) { if (index + 2 < line.Length && line[index + 2] == '_') { result[index++] = new ColoredCharacter('0', NumberColor); continue; } result[index + 0] = new ColoredCharacter('0', NumberColor); result[index + 1] = new ColoredCharacter(nextChar, NumberColor); index += 2; } } bool IsDigit(char c) => char.IsDigit(c) || (format == NumberFormat.Hexadecimal && HexChars.Contains(c)); while (index < line.Length) { var c = line[index]; if (justTake) { justTake = false; result[index++] = new ColoredCharacter(c, NumberColor); continue; } if (c == '_' && (index + 1 < line.Length && IsDigit(line[index + 1]))) { result[index++] = new ColoredCharacter(c, NumberColor); continue; } if (format == NumberFormat.Decimal) { if (c == '.' && !hasDecimal && !hasExp) { hasDecimal = true; if (index + 1 >= line.Length || !IsDigit(line[index + 1])) { break; } result[index++] = new ColoredCharacter(c, NumberColor); continue; } if ((c == 'e' || c == 'E') && !hasExp) { if (index + 1 < line.Length) { var next = line[index + 1]; if (next == '+' || next == '-') { justTake = true; } } hasExp = true; result[index++] = new ColoredCharacter(c, NumberColor); continue; } } if (!IsDigit(c)) { break; } result[index++] = new ColoredCharacter(c, NumberColor); } continue; } result[index] = new ColoredCharacter(line[index], OtherColor); index++; } }
private static Highlighter Redraw() { var inputString = new string(_input.ToArray()); var newHighlighter = _originalHighlighter.Clone(); var currentColors = newHighlighter.Highlight(inputString); SavePosition(); var length = Math.Max(currentColors.Length, _previousColors.Length); int start = 0; for (; start < length; start++) { if (start >= _previousColors.Length || start >= currentColors.Length) { break; } var prev = _previousColors[start]; var curr = currentColors[start]; if (prev.Character != curr.Character || prev.Color != curr.Color) { break; } } Move(-_position + start); ConsoleColor?prevColor = null; for (var i = start; i < length; i++) { var curr = new ColoredCharacter(' ', ConsoleColor.Gray); if (i < currentColors.Length) { curr = currentColors[i]; } if (!prevColor.HasValue || prevColor.Value != curr.Color) { Console.ForegroundColor = curr.Color; } prevColor = curr.Color; Console.Write(curr.Character); _position++; if (Console.CursorLeft == Console.BufferWidth - 1 && Console.CursorTop == Console.BufferHeight - 1) { Console.WriteLine(); Move(-1); _position++; } } RestorePosition(); _previousColors = currentColors; return(newHighlighter); }
private void ColorNone(string line, ColoredCharacter[] result, ref int index) { while (index < line.Length) { if (OutputIfNext(line, result, ref index, "//", CommentColor)) { for (var i = index; i < line.Length; i++, index++) { result[i] = new ColoredCharacter(line[i], CommentColor); } return; } if (OutputIfNext(line, result, ref index, "/*", CommentColor)) { _state = TokenState.MultiComment; _multiCommentDepth = 1; return; } var ch = line[index]; if (OutputIfNext(line, result, ref index, "\"", StringColor) || OutputIfNext(line, result, ref index, "\'", StringColor)) { _state = TokenState.String; _stringTerminator = ch; return; } string[] operators; if (Operators.TryGetValue(ch, out operators)) { var idx = index; var op = operators.FirstOrDefault(s => IsNext(line, idx, s)); if (op != null) { Output(result, ref index, op, OperatorColor); continue; } } if (char.IsLetter(ch) || ch == '_') { var start = index; while (index < line.Length && (char.IsLetterOrDigit(line[index]) || line[index] == '_')) { index++; } var word = line.Substring(start, index - start); index = start; if (Keywords.Contains(word)) { Output(result, ref index, word, KeywordColor); continue; } Output(result, ref index, word, IdentifierColor); continue; } if (char.IsDigit(ch)) { var format = NumberFormat.Decimal; var hasDecimal = false; var hasExp = false; var justTake = false; if (ch == '0' && index + 1 < line.Length) { var nextChar = line[index + 1]; if (nextChar == 'x' || nextChar == 'X') format = NumberFormat.Hexadecimal; if (nextChar == 'b' || nextChar == 'B') format = NumberFormat.Binary; if (format != NumberFormat.Decimal) { if (index + 2 < line.Length && line[index + 2] == '_') { result[index++] = new ColoredCharacter('0', NumberColor); continue; } result[index + 0] = new ColoredCharacter('0', NumberColor); result[index + 1] = new ColoredCharacter(nextChar, NumberColor); index += 2; } } Func<char, bool> isDigit = c => char.IsDigit(c) || (format == NumberFormat.Hexadecimal && HexChars.Contains(c)); while (index < line.Length) { var c = line[index]; if (justTake) { justTake = false; result[index++] = new ColoredCharacter(c, NumberColor); continue; } if (c == '_' && (index + 1 < line.Length && isDigit(line[index + 1]))) { result[index++] = new ColoredCharacter(c, NumberColor); continue; } if (format == NumberFormat.Decimal) { if (c == '.' && !hasDecimal && !hasExp) { hasDecimal = true; if (index + 1 >= line.Length || !isDigit(line[index + 1])) break; result[index++] = new ColoredCharacter(c, NumberColor); continue; } if ((c == 'e' || c == 'E') && !hasExp) { if (index + 1 < line.Length) { var next = line[index + 1]; if (next == '+' || next == '-') justTake = true; } hasExp = true; result[index++] = new ColoredCharacter(c, NumberColor); continue; } } if (!isDigit(c)) break; result[index++] = new ColoredCharacter(c, NumberColor); } continue; } result[index] = new ColoredCharacter(line[index], OtherColor); index++; } }
private void ColorMultiComment(string line, ColoredCharacter[] result, ref int index) { while (_multiCommentDepth > 0) { if (index >= line.Length) return; if (OutputIfNext(line, result, ref index, "/*", CommentColor)) { _multiCommentDepth++; continue; } if (OutputIfNext(line, result, ref index, "*/", CommentColor)) { _multiCommentDepth--; continue; } result[index] = new ColoredCharacter(line[index], CommentColor); index++; } _state = TokenState.None; }
private static bool OutputIfNext(string line, ColoredCharacter[] result, ref int index, string value, ConsoleColor color) { var isNext = IsNext(line, index, value); if (isNext) Output(result, ref index, value, color); return isNext; }