| | | 1 | | @using DiffPlex.DiffBuilder.Model; |
| | | 2 | | |
| | 0 | 3 | | @if (!string.IsNullOrEmpty(Model?.Text)) |
| | | 4 | | { |
| | 0 | 5 | | @if (Model.Type == ChangeType.Unchanged) |
| | | 6 | | { |
| | 0 | 7 | | @Model.Text |
| | | 8 | | } |
| | 0 | 9 | | else if (Model.SubPieces is not null && Model.SubPieces.Count > 0) |
| | | 10 | | { |
| | 0 | 11 | | @foreach (var word in GetWords()) |
| | | 12 | | { |
| | 0 | 13 | | @if (!word.HasChanges) |
| | | 14 | | { |
| | 0 | 15 | | @word.Text |
| | | 16 | | } |
| | 0 | 17 | | else if (word.IsFullyChanged) |
| | | 18 | | { |
| | 0 | 19 | | <span class="@word.CharacterCss">@word.Text</span> |
| | | 20 | | } |
| | | 21 | | else |
| | | 22 | | { |
| | | 23 | | <span class="@word.WordCss"> |
| | 0 | 24 | | @foreach (var ch in word.Characters) |
| | | 25 | | { |
| | 0 | 26 | | @if (ch.IsChanged) |
| | | 27 | | { |
| | 0 | 28 | | <span class="@ch.CssClass">@ch.Text</span> |
| | | 29 | | } |
| | | 30 | | else |
| | | 31 | | { |
| | 0 | 32 | | @ch.Text |
| | | 33 | | } |
| | | 34 | | } |
| | | 35 | | </span> |
| | | 36 | | } |
| | | 37 | | } |
| | | 38 | | } |
| | | 39 | | else |
| | | 40 | | { |
| | 0 | 41 | | @Model.Text |
| | | 42 | | } |
| | | 43 | | } |
| | | 44 | | |
| | | 45 | | @code { |
| | 0 | 46 | | [Parameter, EditorRequired] public DiffPiece Model { get; set; } = default!; |
| | | 47 | | |
| | 0 | 48 | | private sealed record CharInfo(string Text, bool IsChanged, string CssClass); |
| | | 49 | | |
| | 0 | 50 | | private sealed record WordGroup( |
| | 0 | 51 | | string Text, |
| | 0 | 52 | | List<CharInfo> Characters, |
| | 0 | 53 | | bool HasChanges, |
| | 0 | 54 | | bool IsFullyChanged, |
| | 0 | 55 | | string CharacterCss, |
| | 0 | 56 | | string WordCss); |
| | | 57 | | |
| | | 58 | | private List<WordGroup> GetWords() |
| | | 59 | | { |
| | 0 | 60 | | var words = new List<WordGroup>(); |
| | 0 | 61 | | var currentChars = new List<CharInfo>(); |
| | | 62 | | |
| | 0 | 63 | | foreach (var sub in Model.SubPieces) |
| | | 64 | | { |
| | 0 | 65 | | if (sub.Type == ChangeType.Imaginary) continue; |
| | 0 | 66 | | var text = sub.Text ?? ""; |
| | 0 | 67 | | if (text.Length == 0) continue; |
| | | 68 | | |
| | 0 | 69 | | var isChanged = sub.Type != ChangeType.Unchanged; |
| | 0 | 70 | | var info = new CharInfo(text, isChanged, $"{sub.Type.ToString().ToLower()}-character"); |
| | | 71 | | |
| | 0 | 72 | | if (text.All(char.IsWhiteSpace)) |
| | | 73 | | { |
| | 0 | 74 | | if (currentChars.Count > 0) |
| | | 75 | | { |
| | 0 | 76 | | words.Add(BuildWord(currentChars)); |
| | 0 | 77 | | currentChars = []; |
| | | 78 | | } |
| | 0 | 79 | | words.Add(BuildWord([info])); |
| | | 80 | | } |
| | | 81 | | else |
| | | 82 | | { |
| | 0 | 83 | | currentChars.Add(info); |
| | | 84 | | } |
| | | 85 | | } |
| | | 86 | | |
| | 0 | 87 | | if (currentChars.Count > 0) |
| | 0 | 88 | | words.Add(BuildWord(currentChars)); |
| | | 89 | | |
| | 0 | 90 | | return words; |
| | | 91 | | } |
| | | 92 | | |
| | | 93 | | private static WordGroup BuildWord(List<CharInfo> chars) |
| | | 94 | | { |
| | 0 | 95 | | var text = string.Concat(chars.Select(c => c.Text)); |
| | 0 | 96 | | var changed = chars.Where(c => c.IsChanged).ToList(); |
| | 0 | 97 | | var hasChanges = changed.Count > 0; |
| | 0 | 98 | | var isFullyChanged = changed.Count == chars.Count; |
| | 0 | 99 | | var dominantType = changed.FirstOrDefault()?.CssClass.Replace("-character", "") ?? "unchanged"; |
| | | 100 | | |
| | 0 | 101 | | return new WordGroup( |
| | 0 | 102 | | text, |
| | 0 | 103 | | chars, |
| | 0 | 104 | | hasChanges, |
| | 0 | 105 | | isFullyChanged, |
| | 0 | 106 | | $"{dominantType}-character", |
| | 0 | 107 | | $"{dominantType}-word"); |
| | | 108 | | } |
| | | 109 | | } |