diff --git a/DiscordChatExporter.Core.Markdown/Internal/Extensions.cs b/DiscordChatExporter.Core.Markdown/Internal/Extensions.cs index db8c845a..2aac6143 100644 --- a/DiscordChatExporter.Core.Markdown/Internal/Extensions.cs +++ b/DiscordChatExporter.Core.Markdown/Internal/Extensions.cs @@ -1,20 +1,10 @@ using System; using System.Collections.Generic; -using System.Text.RegularExpressions; namespace DiscordChatExporter.Core.Markdown.Internal { internal static class Extensions { - public static StringPart Shrink(this StringPart stringPart, int newStartIndex, int newLength) => - new StringPart(stringPart.Target, newStartIndex, newLength); - - public static StringPart Shrink(this StringPart stringPart, int newStartIndex) => - stringPart.Shrink(newStartIndex, stringPart.EndIndex - newStartIndex); - - public static StringPart Shrink(this StringPart stringPart, Capture capture) => - stringPart.Shrink(capture.Index, capture.Length); - public static IEnumerable> MatchAll(this IMatcher matcher, StringPart stringPart, Func fallbackTransform) { @@ -23,7 +13,7 @@ namespace DiscordChatExporter.Core.Markdown.Internal while (currentIndex < stringPart.EndIndex) { // Find a match within this segment - var match = matcher.Match(stringPart.Shrink(currentIndex, stringPart.EndIndex - currentIndex)); + var match = matcher.Match(stringPart.Slice(currentIndex, stringPart.EndIndex - currentIndex)); // If there's no match - break if (match == null) @@ -32,7 +22,7 @@ namespace DiscordChatExporter.Core.Markdown.Internal // If this match doesn't start immediately at current index - transform and yield fallback first if (match.StringPart.StartIndex > currentIndex) { - var fallbackPart = stringPart.Shrink(currentIndex, match.StringPart.StartIndex - currentIndex); + var fallbackPart = stringPart.Slice(currentIndex, match.StringPart.StartIndex - currentIndex); yield return new ParsedMatch(fallbackPart, fallbackTransform(fallbackPart)); } @@ -46,7 +36,7 @@ namespace DiscordChatExporter.Core.Markdown.Internal // If EOL wasn't reached - transform and yield remaining part as fallback if (currentIndex < stringPart.EndIndex) { - var fallbackPart = stringPart.Shrink(currentIndex); + var fallbackPart = stringPart.Slice(currentIndex); yield return new ParsedMatch(fallbackPart, fallbackTransform(fallbackPart)); } } diff --git a/DiscordChatExporter.Core.Markdown/Internal/RegexMatcher.cs b/DiscordChatExporter.Core.Markdown/Internal/RegexMatcher.cs index a35d92f4..324eba07 100644 --- a/DiscordChatExporter.Core.Markdown/Internal/RegexMatcher.cs +++ b/DiscordChatExporter.Core.Markdown/Internal/RegexMatcher.cs @@ -33,8 +33,8 @@ namespace DiscordChatExporter.Core.Markdown.Internal if (!_regex.IsMatch(stringPart.Target.Substring(0, stringPart.EndIndex), stringPart.StartIndex)) return null; - var stringPartShrunk = stringPart.Shrink(match.Index, match.Length); - return new ParsedMatch(stringPartShrunk, _transform(stringPartShrunk, match)); + var stringPartMatch = stringPart.Slice(match.Index, match.Length); + return new ParsedMatch(stringPartMatch, _transform(stringPartMatch, match)); } } } \ No newline at end of file diff --git a/DiscordChatExporter.Core.Markdown/Internal/StringMatcher.cs b/DiscordChatExporter.Core.Markdown/Internal/StringMatcher.cs index 2722ce56..8639d666 100644 --- a/DiscordChatExporter.Core.Markdown/Internal/StringMatcher.cs +++ b/DiscordChatExporter.Core.Markdown/Internal/StringMatcher.cs @@ -26,8 +26,8 @@ namespace DiscordChatExporter.Core.Markdown.Internal if (index >= 0) { - var stringPartShrunk = stringPart.Shrink(index, _needle.Length); - return new ParsedMatch(stringPartShrunk, _transform(stringPartShrunk)); + var stringPartMatch = stringPart.Slice(index, _needle.Length); + return new ParsedMatch(stringPartMatch, _transform(stringPartMatch)); } return null; diff --git a/DiscordChatExporter.Core.Markdown/Internal/StringPart.cs b/DiscordChatExporter.Core.Markdown/Internal/StringPart.cs index 7a1b55f7..9cb35c42 100644 --- a/DiscordChatExporter.Core.Markdown/Internal/StringPart.cs +++ b/DiscordChatExporter.Core.Markdown/Internal/StringPart.cs @@ -1,6 +1,8 @@ -namespace DiscordChatExporter.Core.Markdown.Internal +using System.Text.RegularExpressions; + +namespace DiscordChatExporter.Core.Markdown.Internal { - internal class StringPart + internal readonly struct StringPart { public string Target { get; } @@ -23,6 +25,12 @@ { } + public StringPart Slice(int newStartIndex, int newLength) => new StringPart(Target, newStartIndex, newLength); + + public StringPart Slice(int newStartIndex) => Slice(newStartIndex, EndIndex - newStartIndex); + + public StringPart Slice(Capture capture) => Slice(capture.Index, capture.Length); + public override string ToString() => Target.Substring(StartIndex, Length); } } \ No newline at end of file diff --git a/DiscordChatExporter.Core.Markdown/MarkdownParser.cs b/DiscordChatExporter.Core.Markdown/MarkdownParser.cs index 36cee885..1cac111d 100644 --- a/DiscordChatExporter.Core.Markdown/MarkdownParser.cs +++ b/DiscordChatExporter.Core.Markdown/MarkdownParser.cs @@ -16,57 +16,57 @@ namespace DiscordChatExporter.Core.Markdown // Capture any character until the earliest double asterisk not followed by an asterisk private static readonly IMatcher BoldFormattedNodeMatcher = new RegexMatcher( new Regex("\\*\\*(.+?)\\*\\*(?!\\*)", DefaultRegexOptions | RegexOptions.Singleline), - (p, m) => new FormattedNode(TextFormatting.Bold, Parse(p.Shrink(m.Groups[1])))); + (p, m) => new FormattedNode(TextFormatting.Bold, Parse(p.Slice(m.Groups[1])))); // Capture any character until the earliest single asterisk not preceded or followed by an asterisk // Opening asterisk must not be followed by whitespace // Closing asterisk must not be preceded by whitespace private static readonly IMatcher ItalicFormattedNodeMatcher = new RegexMatcher( new Regex("\\*(?!\\s)(.+?)(? new FormattedNode(TextFormatting.Italic, Parse(p.Shrink(m.Groups[1])))); + (p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Slice(m.Groups[1])))); // Capture any character until the earliest triple asterisk not followed by an asterisk private static readonly IMatcher ItalicBoldFormattedNodeMatcher = new RegexMatcher( new Regex("\\*(\\*\\*.+?\\*\\*)\\*(?!\\*)", DefaultRegexOptions | RegexOptions.Singleline), - (p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Shrink(m.Groups[1]), BoldFormattedNodeMatcher))); + (p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Slice(m.Groups[1]), BoldFormattedNodeMatcher))); // Capture any character except underscore until an underscore // Closing underscore must not be followed by a word character private static readonly IMatcher ItalicAltFormattedNodeMatcher = new RegexMatcher( new Regex("_([^_]+)_(?!\\w)", DefaultRegexOptions | RegexOptions.Singleline), - (p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Shrink(m.Groups[1])))); + (p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Slice(m.Groups[1])))); // Capture any character until the earliest double underscore not followed by an underscore private static readonly IMatcher UnderlineFormattedNodeMatcher = new RegexMatcher( new Regex("__(.+?)__(?!_)", DefaultRegexOptions | RegexOptions.Singleline), - (p, m) => new FormattedNode(TextFormatting.Underline, Parse(p.Shrink(m.Groups[1])))); + (p, m) => new FormattedNode(TextFormatting.Underline, Parse(p.Slice(m.Groups[1])))); // Capture any character until the earliest triple underscore not followed by an underscore private static readonly IMatcher ItalicUnderlineFormattedNodeMatcher = new RegexMatcher( new Regex("_(__.+?__)_(?!_)", DefaultRegexOptions | RegexOptions.Singleline), - (p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Shrink(m.Groups[1]), UnderlineFormattedNodeMatcher))); + (p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Slice(m.Groups[1]), UnderlineFormattedNodeMatcher))); // Capture any character until the earliest double tilde private static readonly IMatcher StrikethroughFormattedNodeMatcher = new RegexMatcher( new Regex("~~(.+?)~~", DefaultRegexOptions | RegexOptions.Singleline), - (p, m) => new FormattedNode(TextFormatting.Strikethrough, Parse(p.Shrink(m.Groups[1])))); + (p, m) => new FormattedNode(TextFormatting.Strikethrough, Parse(p.Slice(m.Groups[1])))); // Capture any character until the earliest double pipe private static readonly IMatcher SpoilerFormattedNodeMatcher = new RegexMatcher( new Regex("\\|\\|(.+?)\\|\\|", DefaultRegexOptions | RegexOptions.Singleline), - (p, m) => new FormattedNode(TextFormatting.Spoiler, Parse(p.Shrink(m.Groups[1])))); + (p, m) => new FormattedNode(TextFormatting.Spoiler, Parse(p.Slice(m.Groups[1])))); // Capture any character until the end of the line // Opening 'greater than' character must be followed by whitespace private static readonly IMatcher SingleLineQuoteNodeMatcher = new RegexMatcher( new Regex("^>\\s(.+)\r?\n?", DefaultRegexOptions), - (p, m) => new FormattedNode(TextFormatting.Quote, Parse(p.Shrink(m.Groups[1])))); + (p, m) => new FormattedNode(TextFormatting.Quote, Parse(p.Slice(m.Groups[1])))); // Capture any character until the end of the input // Opening 'greater than' characters must be followed by whitespace private static readonly IMatcher MultiLineQuoteNodeMatcher = new RegexMatcher( new Regex("^>>>\\s(.+)", DefaultRegexOptions | RegexOptions.Singleline), - (p, m) => new FormattedNode(TextFormatting.Quote, Parse(p.Shrink(m.Groups[1])))); + (p, m) => new FormattedNode(TextFormatting.Quote, Parse(p.Slice(m.Groups[1])))); /* Code blocks */