mirror of
https://github.com/Stone-Red-Code/YesNt-Interpreter.git
synced 2026-09-04 09:06:41 +02:00
177 lines
7.5 KiB
C#
177 lines
7.5 KiB
C#
using System;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
|
|
using YesNt.Interpreter.Enums;
|
|
using YesNt.Interpreter.Runtime;
|
|
using YesNt.Interpreter.Utilities;
|
|
|
|
namespace YesNt.CodeEditor;
|
|
|
|
internal partial class SyntaxHighlighter(ReadOnlyCollection<StatementInformation> statementInformation)
|
|
{
|
|
private readonly ReadOnlyCollection<StatementInformation> statementInformation = statementInformation;
|
|
private readonly string[] replacementValues = StringExtensions.ReplacementRules.Values.ToArray();
|
|
|
|
public static string Base64Encode(string plainText)
|
|
{
|
|
byte[] plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
|
|
return System.Convert.ToBase64String(plainTextBytes);
|
|
}
|
|
|
|
public static string Base64Decode(string base64EncodedData)
|
|
{
|
|
byte[] base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
|
|
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
|
|
}
|
|
|
|
public void Write(string input)
|
|
{
|
|
input = input.Replace("\0", string.Empty);
|
|
|
|
if (input.TrimStart(' ').StartsWith('#'))
|
|
{
|
|
input = AddColorInformation(input, input, ConsoleColor.Gray, SearchMode.Exact);
|
|
}
|
|
else
|
|
{
|
|
MatchCollection matches = StringRegex().Matches(input);
|
|
for (int i = 0; i < matches.Count; i++)
|
|
{
|
|
input = AddColorInformation(input, matches[i].Value, ConsoleColor.DarkYellow, SearchMode.Contains);
|
|
}
|
|
|
|
matches = VariableRegex().Matches(input);
|
|
for (int i = 0; i < matches.Count; i++)
|
|
{
|
|
input = AddColorInformation(input, matches[i].Value, ConsoleColor.Cyan, SearchMode.Contains);
|
|
}
|
|
|
|
for (int i = 0; i < replacementValues.Length; i++)
|
|
{
|
|
input = AddColorInformation(input, replacementValues[i], ConsoleColor.Blue, SearchMode.Contains);
|
|
}
|
|
|
|
foreach (StatementInformation statement in statementInformation)
|
|
{
|
|
if (statement.IgnoreSyntaxHighlighting)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string name = statement.SpaceAround switch
|
|
{
|
|
SpaceAround.StartEnd => $" {statement.Name.Trim()} ",
|
|
SpaceAround.Start => $" {statement.Name.Trim()}",
|
|
SpaceAround.End => $"{statement.Name.Trim()} ",
|
|
_ => statement.Name.Trim()
|
|
};
|
|
input = input.TrimEnd(' ');
|
|
string inputTrim = input.Trim(' ');
|
|
if (statement.SearchMode == SearchMode.StartOfLine && inputTrim.StartsWith(name))
|
|
{
|
|
if (statement.Separator is not null && input.Contains(statement.Separator))
|
|
{
|
|
input = AddColorInformation(input, statement.Separator, statement.Color, SearchMode.StartOfLine);
|
|
}
|
|
else if (statement.Separator is not null)
|
|
{
|
|
continue;
|
|
}
|
|
input = AddColorInformation(input, name, statement.Color, statement.SearchMode);
|
|
}
|
|
else if (statement.SearchMode == SearchMode.Contains && input.Contains(name))
|
|
{
|
|
if (statement.Separator is not null && input.Contains(statement.Separator))
|
|
{
|
|
input = AddColorInformation(input, statement.Separator, statement.Color, SearchMode.StartOfLine);
|
|
}
|
|
else if (statement.Separator is not null)
|
|
{
|
|
continue;
|
|
}
|
|
input = AddColorInformation(input, input.Substring(input.IndexOf(name), name.Length), statement.Color, statement.SearchMode);
|
|
}
|
|
else if (statement.SearchMode == SearchMode.EndOfLine && input.EndsWith(name))
|
|
{
|
|
if (statement.Separator is not null && input.Contains(statement.Separator))
|
|
{
|
|
input = AddColorInformation(input, statement.Separator, statement.Color, SearchMode.StartOfLine);
|
|
}
|
|
else if (statement.Separator is not null)
|
|
{
|
|
continue;
|
|
}
|
|
input = AddColorInformation(input, input[^name.Length..], statement.Color, statement.SearchMode);
|
|
}
|
|
else if (statement.SearchMode == SearchMode.Exact && inputTrim.Equals(name))
|
|
{
|
|
if (statement.Separator is not null && input.Contains(statement.Separator))
|
|
{
|
|
input = AddColorInformation(input, statement.Separator, statement.Color, SearchMode.StartOfLine);
|
|
}
|
|
else if (statement.Separator is not null)
|
|
{
|
|
continue;
|
|
}
|
|
input = AddColorInformation(input, input, statement.Color, statement.SearchMode);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (string part in input.Split("\0"))
|
|
{
|
|
ConsoleColor consoleColor;
|
|
string messagePart = part;
|
|
|
|
string stringColor = StringColorRegex().Match(messagePart).Value;
|
|
bool succ = int.TryParse(stringColor, out int colorIndex);
|
|
if (succ && colorIndex >= 0 && colorIndex < 16)
|
|
{
|
|
messagePart = Base64Decode(messagePart.Replace("\x01" + stringColor + "\x01", string.Empty));
|
|
consoleColor = (ConsoleColor)colorIndex;
|
|
}
|
|
else
|
|
{
|
|
consoleColor = ConsoleColor.White;
|
|
}
|
|
|
|
if (consoleColor == Console.BackgroundColor)
|
|
{
|
|
consoleColor = ConsoleColor.White;
|
|
}
|
|
Console.ForegroundColor = consoleColor;
|
|
Console.Write(messagePart);
|
|
}
|
|
Console.ForegroundColor = ConsoleColor.Gray;
|
|
}
|
|
|
|
private static string AddColorInformation(string originalString, string value, ConsoleColor color, SearchMode searchMode)
|
|
{
|
|
int spacesAtEnd = value.WhiteSpaceAtEnd();
|
|
|
|
string base64Value = Base64Encode(value.TrimEnd());
|
|
|
|
string result = searchMode switch
|
|
{
|
|
SearchMode.StartOfLine => originalString.ReplaceFirstOccurrence(value, $"\0\x01{(int)color}\x01{base64Value}\0" + new string(' ', spacesAtEnd)),
|
|
SearchMode.EndOfLine => originalString.ReplaceLastOccurrence(value, $"\0\x01{(int)color}\x01{base64Value}\0" + new string(' ', spacesAtEnd)),
|
|
_ => originalString.Replace(value, $"\0\x01{(int)color}\x01{base64Value}\0" + new string(' ', spacesAtEnd))
|
|
};
|
|
return result;
|
|
}
|
|
|
|
// This regex matches variables in the format ${variableName}, where variableName consists of alphanumeric characters.
|
|
[GeneratedRegex("\\$\\{[a-zA-Z0-9]+\\}")]
|
|
private static partial Regex VariableRegex();
|
|
|
|
// This regex matches string literals, taking into account escaped quotes and backslashes.
|
|
[GeneratedRegex(@"(?<!\\)(?:\\\\{2})*""(?:\\.|[^""\\])*""")]
|
|
private static partial Regex StringRegex();
|
|
|
|
// This regex matches the color information embedded in the string, which is in the format \x01{colorIndex}\x01{base64EncodedValue}.
|
|
[GeneratedRegex(@"(?<=(\x01))(.*)(?=\x01)")]
|
|
private static partial Regex StringColorRegex();
|
|
}
|