Code/Dependencies/Pixie/Pixie/Markup/TextDiff.cs
using System;
using System.Collections.Generic;
namespace WasmBox.Pixie.Markup {
/// <summary>
/// A node that visualizes a diff of a pair of strings.
/// </summary>
public sealed class TextDiff : MarkupNode {
/// <summary>
/// Creates a text diff node.
/// </summary>
/// <param name="diff">
/// The diff to render.
/// </param>
/// <param name="operationColors">
/// A dictionary that maps diff operations to the color in which
/// diff elements that use those operations are painted. Diff operations
/// that do not appear as keys in the dictionary are not rendered, except
/// for <see cref="DiffOperation.Unchanged"/>, which is rendered
/// without color if it does not show up as a key.
/// </param>
public TextDiff(
Diff<char> diff,
IReadOnlyDictionary<DiffOperation, Color> operationColors) {
this.Diff = diff;
this.OperationColors = operationColors;
}
/// <summary>
/// Gets the diff to render.
/// </summary>
/// <returns>The diff to render.</returns>
public Diff<char> Diff { get; private set; }
/// <summary>
/// Gets a dictionary that maps diff operations to the color in which
/// diff elements that use those operations are painted. Diff operations
/// that do not appear as keys in the dictionary are not rendered, except
/// for <see cref="DiffOperation.Unchanged"/>, which is rendered
/// without color if it does not show up as a key.
/// </summary>
/// <returns>A mapping of diff operations to colors.</returns>
public IReadOnlyDictionary<DiffOperation, Color> OperationColors { get; private set; }
/// <inheritdoc/>
public override MarkupNode Fallback {
get {
var nodes = new List<MarkupNode>();
int elemCount = Diff.Elements.Count;
for (int i = 0; i < elemCount; i++) {
var elem = Diff.Elements[i];
Color color;
if (OperationColors.TryGetValue(elem.Operation, out color)) {
nodes.Add(
new ColorSpan(
string.Concat( elem.Values),
color));
}
else if (elem.Operation == DiffOperation.Unchanged) {
nodes.Add(string.Concat( elem.Values));
}
}
return new Sequence(nodes);
}
}
/// <inheritdoc/>
public override MarkupNode Map(Func<MarkupNode, MarkupNode> mapping) {
return this;
}
/// <summary>
/// Creates a text diff that renders the deletions in a diff.
/// </summary>
/// <param name="diff">A diff to render.</param>
/// <returns>
/// A text diff node that renders deletions and unchanged diff elements only.
/// </returns>
public static TextDiff RenderDeletions(Diff<char> diff) {
return new TextDiff(
diff,
new Dictionary<DiffOperation, Color>() { { DiffOperation.Deletion, Colors.Red }
});
}
/// <summary>
/// Creates a text diff that renders the insertions in a diff.
/// </summary>
/// <param name="diff">A diff to render.</param>
/// <returns>
/// A text diff node that renders insertions and unchanged diff elements only.
/// </returns>
public static TextDiff RenderInsertions(Diff<char> diff) {
return new TextDiff(
diff,
new Dictionary<DiffOperation, Color>() { { DiffOperation.Insertion, Colors.Green }
});
}
/// <summary>
/// Creates a text diff that renders the both the deletions
/// and insertions in a diff.
/// </summary>
/// <param name="diff">A diff to render.</param>
/// <returns>
/// A text diff node that renders all diff elements.
/// </returns>
public static TextDiff RenderAll(Diff<char> diff) {
return new TextDiff(
diff,
new Dictionary<DiffOperation, Color>() { { DiffOperation.Deletion, Colors.Red }, { DiffOperation.Insertion, Colors.Green }
});
}
}
}