fix(merge): unresolved conflicts compose to empty, not Ours (+ review nits)
All checks were successful
Changelog / changelog (push) Successful in 2s
Release / release (push) Successful in 43s

Code-review follow-ups before push:
- MergeFile.ResultText/Compose() fell back to Ours for unresolved conflicts while
  the editor seeds them empty — align both on empty so the public model matches the
  pane and Continue can't silently auto-accept Ours.
- Bound the gutter re-layout retry (was an unbounded Background re-post when the
  editor isn't laid out, e.g. minimized).
- Pluralize the readout ('1 conflict' not '1 conflicts'). Tests updated. Ui 128 green.
This commit is contained in:
Mika Kuns
2026-06-19 13:14:51 +02:00
parent 29a294b7f3
commit 23a93ce0bb
4 changed files with 18 additions and 10 deletions

View File

@@ -72,9 +72,11 @@ public sealed class MergeFile
/// <summary>A binary file can't be resolved in-app; a text file is done once every block is resolved.</summary>
public bool AllResolved => !IsBinary && Conflicts.All(c => c.IsResolved);
/// <summary>Reassemble the file: stable text verbatim, each conflict replaced by its resolution.</summary>
/// <summary>Reassemble the file: stable text verbatim, each conflict replaced by its resolution
/// (empty when unresolved — the same "empty start" the editor shows; Continue is gated on
/// <see cref="AllResolved"/> so an unresolved conflict never actually reaches here).</summary>
public string Compose() => string.Concat(
Segments.Select(s => s.IsConflict ? (s.Conflict!.Resolution ?? s.Conflict.Ours) : s.StableText));
Segments.Select(s => s.IsConflict ? (s.Conflict!.Resolution ?? "") : s.StableText));
/// <summary>Left pane document: stable regions verbatim, conflict regions show Ours text.</summary>
public string OursText => string.Concat(
@@ -84,7 +86,8 @@ public sealed class MergeFile
public string TheirsText => string.Concat(
Segments.Select(s => s.IsConflict ? s.Conflict!.Theirs : s.StableText));
/// <summary>Middle (result) pane document: stable regions verbatim, conflict regions show Resolution if set, else Ours.</summary>
/// <summary>Middle (result) pane document: stable regions verbatim, conflict regions show the
/// chosen Resolution, or empty when unresolved (the editor builds each conflict up from empty).</summary>
public string ResultText => string.Concat(
Segments.Select(s => s.IsConflict ? (s.Conflict!.Resolution ?? s.Conflict.Ours) : s.StableText));
Segments.Select(s => s.IsConflict ? (s.Conflict!.Resolution ?? "") : s.StableText));
}

View File

@@ -81,7 +81,7 @@ public sealed partial class ConflictResolverViewModel : ObservableObject
if (ActiveFile is null || ActiveFile.Conflicts.Count == 0) return "No text conflicts";
var count = ActiveFile.Conflicts.Count;
var resolved = ActiveFile.Conflicts.Count(c => c.IsResolved);
return $"{count} conflicts · {resolved} resolved";
return $"{count} {(count == 1 ? "conflict" : "conflicts")} · {resolved} resolved";
}
}