| @@ -1,23 +1,91 @@ | |||
| using System.Text; | |||
| using Discord.Net.API; | |||
| using System.Text; | |||
| using System.Text.RegularExpressions; | |||
| namespace Discord | |||
| { | |||
| public static class Format | |||
| public static class Format | |||
| { | |||
| private static readonly Regex _escapeRegex; | |||
| private static readonly MatchEvaluator _escapeEvaluator; | |||
| private static readonly string[] _patterns; | |||
| private static readonly StringBuilder _builder; | |||
| static Format() | |||
| { | |||
| const string innerPattern = "[_*]|~~"; | |||
| _escapeRegex = new Regex($@"(?<=^|\W)(?:{innerPattern})|(?:{innerPattern})(?=\W|$)|\\", RegexOptions.Compiled); | |||
| _escapeEvaluator = new MatchEvaluator(e => '\\' + e.Value); | |||
| } | |||
| _patterns = new string[] { "__", "_", "**", "*", "~~" }; | |||
| _builder = new StringBuilder(DiscordAPIClient.MaxMessageSize); | |||
| } | |||
| /// <summary> Removes all special formatting characters from the provided text. </summary> | |||
| private static string Escape(string text) | |||
| => _escapeRegex.Replace(text, _escapeEvaluator); | |||
| { | |||
| lock (_builder) | |||
| { | |||
| _builder.Clear(); | |||
| //Escape all backslashes | |||
| for (int i = 0; i < text.Length; i++) | |||
| { | |||
| _builder.Append(text[i]); | |||
| if (text[i] == '\\') | |||
| _builder.Append('\\'); | |||
| } | |||
| EscapeSubstring(0, _builder.Length); | |||
| return _builder.ToString(); | |||
| } | |||
| } | |||
| private static int EscapeSubstring(int start, int end) | |||
| { | |||
| int totalAddedChars = 0; | |||
| for (int i = start; i < end + totalAddedChars; i++) | |||
| { | |||
| for (int p = 0; p < _patterns.Length; p++) | |||
| { | |||
| string pattern = _patterns[p]; | |||
| if (i + pattern.Length * 2 > _builder.Length) | |||
| continue; | |||
| int s = FindPattern(pattern, i, i + 1); | |||
| if (s == -1) continue; | |||
| int e = FindPattern(pattern, i + 1, end + totalAddedChars); | |||
| if (e == -1) continue; | |||
| if (e - s - pattern.Length > 0) | |||
| { | |||
| //By going right to left, we dont need to adjust any offsets | |||
| for (int k = pattern.Length - 1; k >= 0; k--) | |||
| _builder.Insert(e + k, '\\'); | |||
| for (int k = pattern.Length - 1; k >= 0; k--) | |||
| _builder.Insert(s + k, '\\'); | |||
| int addedChars = pattern.Length * 2; | |||
| addedChars += EscapeSubstring(s + pattern.Length * 2, e + pattern.Length); | |||
| i = e + addedChars + pattern.Length - 1; | |||
| totalAddedChars += addedChars; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| return totalAddedChars; | |||
| } | |||
| private static int FindPattern(string pattern, int start, int end) | |||
| { | |||
| for (int j = start; j < end; j++) | |||
| { | |||
| if (_builder[j] == '\\') | |||
| { | |||
| j++; | |||
| continue; | |||
| } | |||
| for (int k = 0; k < pattern.Length; k++) | |||
| { | |||
| if (_builder[j + k] != pattern[k]) | |||
| goto nextpos; | |||
| } | |||
| return j; | |||
| nextpos:; | |||
| } | |||
| return -1; | |||
| } | |||
| /// <summary> Returns a markdown-formatted string with no formatting, optionally escaping the contents. </summary> | |||
| public static string Normal(string text, bool escape = true) | |||