Summary Update.
This commit is contained in:
@@ -12,6 +12,12 @@ public static class MarkdownHelper
|
||||
private static readonly Color MentionBg = Color.FromArgb("#2D2F5C");
|
||||
private static readonly Color SpoilerBg = Color.FromArgb("#1F1F23");
|
||||
|
||||
/// <summary>
|
||||
/// The entry point. Returns either a single Label (simple inline text) or a
|
||||
/// VerticalStackLayout (anything with paragraphs, code blocks, or headers).
|
||||
/// First pass extracts fenced code blocks (verbatim, can span multiple lines), then
|
||||
/// AppendTextSegment handles per-line headers and the inline parser.
|
||||
/// </summary>
|
||||
public static View Render(string markdown, double fontSize = 14)
|
||||
{
|
||||
if (string.IsNullOrEmpty(markdown))
|
||||
@@ -37,6 +43,11 @@ public static class MarkdownHelper
|
||||
return stack.Children.Count == 1 ? (View)stack.Children[0] : stack;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a non-code segment by newline and emits the right view per line. Headers/subtext
|
||||
/// get their own labels; consecutive normal lines accumulate into a paragraph buffer so
|
||||
/// they wrap naturally as one paragraph.
|
||||
/// </summary>
|
||||
private static void AppendTextSegment(VerticalStackLayout stack, string segment, double fontSize)
|
||||
{
|
||||
var paragraphBuffer = new StringBuilder();
|
||||
@@ -94,6 +105,10 @@ public static class MarkdownHelper
|
||||
FlushParagraph();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the dark-pane code block. If a language is specified, delegates token coloring
|
||||
/// to SyntaxHighlighter and prepends a small green language label (Discord-style).
|
||||
/// </summary>
|
||||
private static View CreateCodeBlock(string language, string code)
|
||||
{
|
||||
var label = new Label
|
||||
@@ -141,6 +156,7 @@ public static class MarkdownHelper
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>Bold, larger Label for # / ## / ### lines. Inline markdown still works inside (e.g. `# Hello **world**`).</summary>
|
||||
private static Label CreateHeaderLabel(string text, double size)
|
||||
{
|
||||
var label = new Label
|
||||
@@ -162,6 +178,7 @@ public static class MarkdownHelper
|
||||
return label;
|
||||
}
|
||||
|
||||
/// <summary>Smaller, grey Label for "-#" lines (Discord calls it subtext). Inherits inline markdown.</summary>
|
||||
private static Label CreateSubtextLabel(string text, double size)
|
||||
{
|
||||
var label = new Label
|
||||
@@ -190,6 +207,7 @@ public static class MarkdownHelper
|
||||
return label;
|
||||
}
|
||||
|
||||
/// <summary>Standard paragraph Label. Runs the inline parser to build a FormattedString of spans.</summary>
|
||||
private static Label CreateInlineLabel(string text, double fontSize)
|
||||
{
|
||||
var label = new Label { FontSize = fontSize, LineBreakMode = LineBreakMode.WordWrap };
|
||||
@@ -204,6 +222,11 @@ public static class MarkdownHelper
|
||||
return label;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attaches a TapGestureRecognizer that reveals every spoiler span in the label when
|
||||
/// tapped once. MAUI Spans can't fire their own gesture events, so per-spoiler reveal
|
||||
/// would require splitting the line into separate labels — this is the pragmatic compromise.
|
||||
/// </summary>
|
||||
private static void WireSpoilerTap(Label label, List<Span> spoilerSpans)
|
||||
{
|
||||
if (spoilerSpans.Count == 0) return;
|
||||
@@ -220,6 +243,12 @@ public static class MarkdownHelper
|
||||
label.GestureRecognizers.Add(tap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Single-pass character walk. For each markdown sigil (||, @, ~~, __, **, *, `), tries
|
||||
/// to find a matching closer; if found, emits a styled Span and skips past. Otherwise the
|
||||
/// char accumulates into a "plain" buffer that's flushed as a plain Span when the next
|
||||
/// sigil hits or the string ends. Spoiler spans are registered in spoilerSpans for reveal.
|
||||
/// </summary>
|
||||
private static void ParseInline(string text, IList<Span> spans, double fontSize, List<Span> spoilerSpans)
|
||||
{
|
||||
var plain = new StringBuilder();
|
||||
@@ -365,8 +394,13 @@ public static class MarkdownHelper
|
||||
Flush();
|
||||
}
|
||||
|
||||
/// <summary>Safe one-character lookahead. Returns '\0' past end-of-string.</summary>
|
||||
private static char Peek(string text, int index) => index < text.Length ? text[index] : '\0';
|
||||
|
||||
/// <summary>
|
||||
/// Finds the next single occurrence of marker that is NOT immediately followed by
|
||||
/// another marker. Used to disambiguate "*italic*" from "**bold**".
|
||||
/// </summary>
|
||||
private static int FindClosingSingle(string text, char marker, int start)
|
||||
{
|
||||
for (int i = start; i < text.Length; i++)
|
||||
|
||||
Reference in New Issue
Block a user