using Blog.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
namespace Blog.Components.Pages.Git;
///
/// One line of code, as the spans git.css can tell apart.
///
///
/// A render tree rather than markup because the cell this lands in is white-space: pre: any
/// newline or indentation a .razor file left between two tokens would be rendered as part of the
/// file. A render tree emits exactly the nodes it is handed, and AddContent escapes them.
///
public sealed class GitCode : ComponentBase
{
[Parameter]
public IReadOnlyList Tokens { get; set; } = [];
///
/// A diff's + or -, repeated out of the gutter into the line so the diff still
/// reads as one when it is copied or read without colour. git.css marks it unselectable, so
/// copying gives back the code rather than the patch.
///
[Parameter]
public char? Sign { get; set; }
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
// Sequence numbers exist for diffing one render against the next, which these pages never
// do - they are rendered once, statically, and thrown away.
var sequence = 0;
if (Sign is { } sign)
{
builder.OpenElement(sequence++, "span");
builder.AddAttribute(sequence++, "class", "sign");
builder.AddContent(sequence++, sign);
builder.CloseElement();
}
foreach (var token in Tokens)
{
if (token.Kind is SyntaxKind.Text)
{
builder.AddContent(sequence++, token.Text);
continue;
}
builder.OpenElement(sequence++, "span");
builder.AddAttribute(sequence++, "class", Class(token.Kind));
builder.AddContent(sequence++, token.Text);
builder.CloseElement();
}
}
private static string Class(SyntaxKind kind) => kind switch
{
SyntaxKind.Comment => "tok-comment",
SyntaxKind.String => "tok-string",
SyntaxKind.Number => "tok-number",
SyntaxKind.Keyword => "tok-keyword",
SyntaxKind.Meta => "tok-meta",
_ => ""
};
}