Files
YesNt-Interpreter/YesNt.CodeEditor/SyntaxHighlighter.cs
T
2026-03-04 14:04:00 +01:00

182 lines
7.4 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.StartsWith('#'))
{
input = AddColorInformation(input, input, ConsoleColor.Gray, SearchMode.Exact);
}
else
{
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(' ');
if (statement.SearchMode == SearchMode.StartOfLine && input.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, input[..name.Length], 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 && input.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);
}
}
MatchCollection matches = VariableRegex().Matches(input);
for (int i = 0; i < matches.Count; i++)
{
input = AddColorInformation(input, matches[i].Value, ConsoleColor.Cyan, SearchMode.Contains);
}
matches = VariableDeclarationRegex().Matches(input);
for (int i = 0; i < matches.Count; i++)
{
input = AddColorInformation(input, matches[i].Value, ConsoleColor.DarkCyan, SearchMode.StartOfLine);
}
matches = GlobalVariableDeclarationRegex().Matches(input);
for (int i = 0; i < matches.Count; i++)
{
input = AddColorInformation(input, matches[i].Value, ConsoleColor.Blue, SearchMode.StartOfLine);
}
}
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($"\v{stringColor}\v", 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\v{(int)color}\v{base64Value}\0" + new string(' ', spacesAtEnd)),
SearchMode.EndOfLine => originalString.ReplaceLastOccurrence(value, $"\0\v{(int)color}\v{base64Value}\0" + new string(' ', spacesAtEnd)),
_ => originalString.Replace(value, $"\0\v{(int)color}\v{base64Value}\0" + new string(' ', spacesAtEnd))
};
return result;
}
[GeneratedRegex("^let\\s+[a-zA-Z0-9]+")]
private static partial Regex VariableDeclarationRegex();
[GeneratedRegex("^global\\s+[a-zA-Z0-9]+")]
private static partial Regex GlobalVariableDeclarationRegex();
[GeneratedRegex("\\$\\{[a-zA-Z0-9]+\\}")]
private static partial Regex VariableRegex();
[GeneratedRegex("(?<=(\\v))(.*)(?=\\v)")]
private static partial Regex StringColorRegex();
}