Highlighted code blocks inside the app (#1153)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-11-04 07:58:57 +01:00
1 parent 0b42c0288e
commit f4a86c2fb8
60 files changed
+2550 -41

No files matched your search

@@ -0,0 +1,55 @@
using AIStudio.Tools.CodeHighlighting;
using Microsoft.AspNetCore.Components.Rendering;
namespace AIStudio.Components;
/// <summary>
/// Renders Markdown the way MudMarkdown does, and highlights the code blocks of more languages than
/// the library does, such as Python or SQL.
/// </summary>
/// <remarks>
/// MudBlazor.Markdown highlights only a few languages itself, and its highlighter is internal.
/// MudMarkdown renders every code block through RenderCodeBlock, though, and lets us override that.
/// A block in one of the languages of CodeHighlighters becomes a HighlightedCodeBlock; any other block
/// stays as the library renders it. A block which names no language gets the one its code is written in,
/// see CodeLanguageDetector, the same as when it is saved as a file.
/// </remarks>
public class HighlightedMarkdown : MudMarkdown
{
/// <summary>
/// The text of a code block: its lines, each with the line break it came with.
/// </summary>
/// <param name="code">The code block, as Markdig read it.</param>
/// <returns>The text of the block.</returns>
internal static string TextOf(Markdig.Syntax.CodeBlock code) => code.Lines.ToString();
#region Overrides of MudMarkdown
/// <inheritdoc />
protected override void RenderCodeBlock(in RenderTreeBuilder builder, ref int elementIndex, in Markdig.Syntax.CodeBlock code, in string? info)
{
var text = TextOf(code);
var language = CodeLanguageDetector.FenceLanguageOf(info, text);
if (!CodeHighlighters.TryGetRules(language, out _))
{
//
// The copy button of the library confirms in the language of the app, as ours does:
//
this.Styling.CodeBlock.CopyButtonText = CodeBlockCopyButton.ConfirmationText;
base.RenderCodeBlock(builder, ref elementIndex, code, language);
return;
}
//
// Our frames are numbered by their place in this method, as Blazor asks for. The frames of
// the library keep the running count it hands through every render method instead:
//
builder.OpenComponent<HighlightedCodeBlock>(0);
builder.AddComponentParameter(1, nameof(HighlightedCodeBlock.Code), text);
builder.AddComponentParameter(2, nameof(HighlightedCodeBlock.Language), language);
builder.CloseComponent();
}
#endregion
}