using Microsoft.CodeAnalysis; using System.Collections.Immutable; using System.Text.RegularExpressions; using System.Text; namespace RobotNet.WebApp.Scripts.Monaco; public enum MarkdownFormat { Default, Italicize, FirstLineAsCSharp, FirstLineDefaultRestCSharp, AllTextAsCSharp } public static class MarkdownHelpers { private static readonly Regex EscapeRegex = new("([\\\\`\\*_\\{\\}\\[\\]\\(\\)#+\\-\\.!])", RegexOptions.Compiled); private const string ContainerStart = "ContainerStart"; private const string ContainerEnd = "ContainerEnd"; public static string Escape(string markdown) => string.IsNullOrEmpty(markdown) ? string.Empty : EscapeRegex.Replace(markdown, "\\$1"); public static void TaggedTextToMarkdown(ImmutableArray taggedParts, StringBuilder stringBuilder, string newLine, MarkdownFormat markdownFormat, out bool endedWithLineBreak) { bool isInCodeBlock = false; bool brokeLine = true; bool afterFirstLine = false; if (markdownFormat == MarkdownFormat.Italicize) { stringBuilder.Append('_'); } int num = 0; while (num < taggedParts.Length) { TaggedText taggedText = taggedParts[num]; bool flag; if (brokeLine && markdownFormat != MarkdownFormat.Italicize) { brokeLine = false; if (!afterFirstLine) { if (markdownFormat != MarkdownFormat.FirstLineAsCSharp) { goto IL_00a2; } flag = true; } else { if (markdownFormat != MarkdownFormat.FirstLineDefaultRestCSharp) { goto IL_00a2; } flag = true; } goto IL_00bf; } goto IL_0279; IL_00a2: flag = markdownFormat == MarkdownFormat.AllTextAsCSharp; goto IL_00bf; IL_0279: switch (taggedText.Tag) { case "Text": if (!isInCodeBlock) { addText(taggedText.Text); break; } endBlock(); addText(taggedText.Text); break; case "Space": if (isInCodeBlock) { if (indexIsTag(num + 1, ["Text"])) { endBlock(); } addText(taggedText.Text); break; } goto case "Punctuation"; case "Punctuation": addText(taggedText.Text); break; case ContainerStart: addNewline(); addText(taggedText.Text); break; case ContainerEnd: addNewline(); break; case "LineBreak": if (stringBuilder.Length != 0 && !indexIsTag(num + 1, [ContainerStart, ContainerEnd]) && num + 1 != taggedParts.Length) { addNewline(); } break; default: if (!isInCodeBlock) { isInCodeBlock = true; stringBuilder.Append('`'); } stringBuilder.Append(taggedText.Text); brokeLine = false; break; } num++; continue; IL_00bf: bool flag2 = flag; if (!flag2) { for (int j = num; j < taggedParts.Length; flag2 = true, j++) { switch (taggedParts[j].Tag) { case "Text": flag2 = false; break; default: continue; case ContainerStart: case ContainerEnd: case "LineBreak": break; } break; } } else { flag2 = !indexIsTag(num, [ ContainerStart, ContainerEnd, "LineBreak" ]); } if (flag2) { afterFirstLine = true; stringBuilder.Append("```csharp"); stringBuilder.Append(newLine); while (true) { if (num < taggedParts.Length) { taggedText = taggedParts[num]; if (taggedText.Tag == ContainerStart || taggedText.Tag == ContainerEnd || taggedText.Tag == "LineBreak") { stringBuilder.Append(newLine); if (markdownFormat != MarkdownFormat.AllTextAsCSharp && markdownFormat != MarkdownFormat.FirstLineDefaultRestCSharp) { break; } } else { stringBuilder.Append(taggedText.Text); } num++; continue; } stringBuilder.Append(newLine); stringBuilder.Append("```"); endedWithLineBreak = false; return; } stringBuilder.Append("```"); } goto IL_0279; } if (isInCodeBlock) { endBlock(); } if (!brokeLine && markdownFormat == MarkdownFormat.Italicize) { stringBuilder.Append('_'); } endedWithLineBreak = brokeLine; void addNewline() { if (isInCodeBlock) { endBlock(); } if (markdownFormat == MarkdownFormat.Italicize) { stringBuilder.Append('_'); } stringBuilder.Append(newLine); stringBuilder.Append(newLine); brokeLine = true; if (markdownFormat == MarkdownFormat.Italicize) { stringBuilder.Append('_'); } } void addText(string text) { brokeLine = false; afterFirstLine = true; if (!isInCodeBlock) { text = Escape(text); } stringBuilder.Append(text); } void endBlock() { stringBuilder.Append('`'); isInCodeBlock = false; } bool indexIsTag(int i, string[] tags) { if (i < taggedParts.Length) { return tags.Contains(taggedParts[i].Tag); } return false; } } }