From 9711a8cca42a18c910482f50107e7accf6895f81 Mon Sep 17 00:00:00 2001 From: Alexey Golub Date: Tue, 14 Apr 2020 22:27:29 +0300 Subject: [PATCH] [HTML] Match repeated single quotes as a multiline quote Closes #288 --- .../MarkdownParser.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/DiscordChatExporter.Core.Markdown/MarkdownParser.cs b/DiscordChatExporter.Core.Markdown/MarkdownParser.cs index 2dfd67d..054be0a 100644 --- a/DiscordChatExporter.Core.Markdown/MarkdownParser.cs +++ b/DiscordChatExporter.Core.Markdown/MarkdownParser.cs @@ -59,9 +59,19 @@ namespace DiscordChatExporter.Core.Markdown // 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), + new Regex("^>\\s(.+\n?)", DefaultRegexOptions), (p, m) => new FormattedNode(TextFormatting.Quote, Parse(p.Slice(m.Groups[1])))); + // Repeatedly capture any character until the end of the line + // This one is tricky as it ends up producing multiple separate captures + private static readonly IMatcher RepeatedSingleLineQuoteNodeMatcher = new RegexMatcher( + new Regex("(?:^>\\s(.+\n?)){2,}", DefaultRegexOptions), + (p, m) => + { + var children = m.Groups[1].Captures.Select(c => c.Value).SelectMany(Parse).ToArray(); + return new FormattedNode(TextFormatting.Quote, children); + }); + // 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( @@ -188,6 +198,7 @@ namespace DiscordChatExporter.Core.Markdown StrikethroughFormattedNodeMatcher, SpoilerFormattedNodeMatcher, MultiLineQuoteNodeMatcher, + RepeatedSingleLineQuoteNodeMatcher, SingleLineQuoteNodeMatcher, // Code blocks @@ -208,7 +219,8 @@ namespace DiscordChatExporter.Core.Markdown // Emoji StandardEmojiNodeMatcher, - CustomEmojiNodeMatcher); + CustomEmojiNodeMatcher + ); // Minimal set of matchers for non-multimedia formats (e.g. plain text) private static readonly IMatcher MinimalAggregateNodeMatcher = new AggregateMatcher( @@ -220,7 +232,8 @@ namespace DiscordChatExporter.Core.Markdown RoleMentionNodeMatcher, // Emoji - CustomEmojiNodeMatcher); + CustomEmojiNodeMatcher + ); private static IReadOnlyList Parse(StringPart stringPart, IMatcher matcher) => matcher.MatchAll(stringPart, p => new TextNode(p.ToString())).Select(r => r.Value).ToArray();