From ef53dd0025bb5f87c0252581812f52beb168dd0d Mon Sep 17 00:00:00 2001 From: leo Date: Sat, 24 May 2025 20:25:05 +0800 Subject: [PATCH] refactor: use a new `Models.ChangeState.Conflicted` to represent all the `unmerged` file state (#1359) Signed-off-by: leo --- src/Commands/QueryLocalChanges.cs | 18 +-- src/Commands/QueryStagedChangesWithAmend.cs | 119 ++++++++++---------- src/Models/Change.cs | 20 +--- src/ViewModels/Conflict.cs | 1 - src/ViewModels/WorkingCopy.cs | 35 +++--- src/Views/ChangeStatusIcon.cs | 29 +---- 6 files changed, 87 insertions(+), 135 deletions(-) diff --git a/src/Commands/QueryLocalChanges.cs b/src/Commands/QueryLocalChanges.cs index 404f5be6..9abf433e 100644 --- a/src/Commands/QueryLocalChanges.cs +++ b/src/Commands/QueryLocalChanges.cs @@ -128,30 +128,16 @@ namespace SourceGit.Commands change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied); break; case "DD": - change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted); - break; case "AU": - change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged); - break; case "UD": - change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted); - break; case "UA": - change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added); - break; case "DU": - change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged); - break; case "AA": - change.Set(Models.ChangeState.Added, Models.ChangeState.Added); - break; case "UU": - change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged); + change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted); break; case "??": - change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked); - break; - default: + change.Set(Models.ChangeState.None, Models.ChangeState.Untracked); break; } diff --git a/src/Commands/QueryStagedChangesWithAmend.cs b/src/Commands/QueryStagedChangesWithAmend.cs index 8f8456c9..b20c20dc 100644 --- a/src/Commands/QueryStagedChangesWithAmend.cs +++ b/src/Commands/QueryStagedChangesWithAmend.cs @@ -6,7 +6,7 @@ namespace SourceGit.Commands { public partial class QueryStagedChangesWithAmend : Command { - [GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} ([ACDMTUX])\d{0,6}\t(.*)$")] + [GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} ([ACDMT])\d{0,6}\t(.*)$")] private static partial Regex REG_FORMAT1(); [GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} R\d{0,6}\t(.*\t.*)$")] private static partial Regex REG_FORMAT2(); @@ -22,76 +22,71 @@ namespace SourceGit.Commands public List Result() { var rs = ReadToEnd(); - if (rs.IsSuccess) + if (!rs.IsSuccess) + return []; + + var changes = new List(); + var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) { - var changes = new List(); - var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); - foreach (var line in lines) + var match = REG_FORMAT2().Match(line); + if (match.Success) { - var match = REG_FORMAT2().Match(line); - if (match.Success) + var change = new Models.Change() { - var change = new Models.Change() + Path = match.Groups[3].Value, + DataForAmend = new Models.ChangeDataForAmend() { - Path = match.Groups[3].Value, - DataForAmend = new Models.ChangeDataForAmend() - { - FileMode = match.Groups[1].Value, - ObjectHash = match.Groups[2].Value, - ParentSHA = _parent, - }, - }; - change.Set(Models.ChangeState.Renamed); - changes.Add(change); - continue; - } - - match = REG_FORMAT1().Match(line); - if (match.Success) - { - var change = new Models.Change() - { - Path = match.Groups[4].Value, - DataForAmend = new Models.ChangeDataForAmend() - { - FileMode = match.Groups[1].Value, - ObjectHash = match.Groups[2].Value, - ParentSHA = _parent, - }, - }; - - var type = match.Groups[3].Value; - switch (type) - { - case "A": - change.Set(Models.ChangeState.Added); - break; - case "C": - change.Set(Models.ChangeState.Copied); - break; - case "D": - change.Set(Models.ChangeState.Deleted); - break; - case "M": - change.Set(Models.ChangeState.Modified); - break; - case "T": - change.Set(Models.ChangeState.TypeChanged); - break; - case "U": - change.Set(Models.ChangeState.Unmerged); - break; - } - changes.Add(change); - } + FileMode = match.Groups[1].Value, + ObjectHash = match.Groups[2].Value, + ParentSHA = _parent, + }, + }; + change.Set(Models.ChangeState.Renamed); + changes.Add(change); + continue; } - return changes; + match = REG_FORMAT1().Match(line); + if (match.Success) + { + var change = new Models.Change() + { + Path = match.Groups[4].Value, + DataForAmend = new Models.ChangeDataForAmend() + { + FileMode = match.Groups[1].Value, + ObjectHash = match.Groups[2].Value, + ParentSHA = _parent, + }, + }; + + var type = match.Groups[3].Value; + switch (type) + { + case "A": + change.Set(Models.ChangeState.Added); + break; + case "C": + change.Set(Models.ChangeState.Copied); + break; + case "D": + change.Set(Models.ChangeState.Deleted); + break; + case "M": + change.Set(Models.ChangeState.Modified); + break; + case "T": + change.Set(Models.ChangeState.TypeChanged); + break; + } + changes.Add(change); + } } - return []; + return changes; } - private string _parent = string.Empty; + private readonly string _parent; } } diff --git a/src/Models/Change.cs b/src/Models/Change.cs index 0c96ec95..7d772d3e 100644 --- a/src/Models/Change.cs +++ b/src/Models/Change.cs @@ -18,8 +18,8 @@ namespace SourceGit.Models Deleted, Renamed, Copied, - Unmerged, - Untracked + Untracked, + Conflicted, } public class ChangeDataForAmend @@ -36,20 +36,7 @@ namespace SourceGit.Models public string Path { get; set; } = ""; public string OriginalPath { get; set; } = ""; public ChangeDataForAmend DataForAmend { get; set; } = null; - - public bool IsConflict - { - get - { - if (Index == ChangeState.Unmerged || WorkTree == ChangeState.Unmerged) - return true; - if (Index == ChangeState.Added && WorkTree == ChangeState.Added) - return true; - if (Index == ChangeState.Deleted && WorkTree == ChangeState.Deleted) - return true; - return false; - } - } + public bool IsConflicted => WorkTree == ChangeState.Conflicted; public void Set(ChangeState index, ChangeState workTree = ChangeState.None) { @@ -77,6 +64,7 @@ namespace SourceGit.Models if (Path[0] == '"') Path = Path.Substring(1, Path.Length - 2); + if (!string.IsNullOrEmpty(OriginalPath) && OriginalPath[0] == '"') OriginalPath = OriginalPath.Substring(1, OriginalPath.Length - 2); } diff --git a/src/ViewModels/Conflict.cs b/src/ViewModels/Conflict.cs index e3197f8f..add365a3 100644 --- a/src/ViewModels/Conflict.cs +++ b/src/ViewModels/Conflict.cs @@ -49,7 +49,6 @@ namespace SourceGit.ViewModels _change = change; var isSubmodule = repo.Submodules.Find(x => x.Path.Equals(change.Path, StringComparison.Ordinal)) != null; - IsResolved = !isSubmodule && new Commands.IsConflictResolved(repo.FullPath, change).Result(); var context = wc.InProgressContext; diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 1c0e2a74..7c2d95f9 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -244,7 +244,7 @@ namespace SourceGit.ViewModels // Just force refresh selected changes. Dispatcher.UIThread.Invoke(() => { - HasUnsolvedConflicts = _cached.Find(x => x.IsConflict) != null; + HasUnsolvedConflicts = _cached.Find(x => x.IsConflicted) != null; UpdateDetail(); UpdateInProgressState(); @@ -276,7 +276,7 @@ namespace SourceGit.ViewModels if (c.WorkTree != Models.ChangeState.None) { unstaged.Add(c); - hasConflict |= c.IsConflict; + hasConflict |= c.IsConflicted; } } @@ -378,7 +378,7 @@ namespace SourceGit.ViewModels foreach (var change in changes) { - if (!change.IsConflict) + if (!change.IsConflicted) continue; if (change.WorkTree == Models.ChangeState.Deleted) @@ -420,7 +420,7 @@ namespace SourceGit.ViewModels foreach (var change in changes) { - if (!change.IsConflict) + if (!change.IsConflicted) continue; if (change.Index == Models.ChangeState.Deleted) @@ -547,17 +547,17 @@ namespace SourceGit.ViewModels public void Commit() { - DoCommit(false, false, false); + DoCommit(false, false); } public void CommitWithAutoStage() { - DoCommit(true, false, false); + DoCommit(true, false); } public void CommitWithPush() { - DoCommit(false, true, false); + DoCommit(false, true); } public ContextMenu CreateContextMenuForUnstagedChanges() @@ -594,7 +594,7 @@ namespace SourceGit.ViewModels menu.Items.Add(openWith); menu.Items.Add(new MenuItem() { Header = "-" }); - if (change.IsConflict) + if (change.IsConflicted) { var useTheirs = new MenuItem(); useTheirs.Icon = App.CreateMenuIcon("Icons.Incoming"); @@ -949,7 +949,7 @@ namespace SourceGit.ViewModels var hasNonConflicts = false; foreach (var change in _selectedUnstaged) { - if (change.IsConflict) + if (change.IsConflicted) hasConflicts = true; else hasNonConflicts = true; @@ -1534,9 +1534,7 @@ namespace SourceGit.ViewModels var rs = new List(); foreach (var c in _cached) { - if (c.Index != Models.ChangeState.None && - c.Index != Models.ChangeState.Untracked && - !c.IsConflict) + if (c.Index != Models.ChangeState.None) rs.Add(c); } return rs; @@ -1682,7 +1680,7 @@ namespace SourceGit.ViewModels if (change == null) DetailContext = null; - else if (change.IsConflict && isUnstaged) + else if (change.IsConflicted) DetailContext = new Conflict(_repo, this, change); else DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged), _detailContext as DiffContext); @@ -1764,14 +1762,17 @@ namespace SourceGit.ViewModels { if (old.Count != cur.Count) return true; - - var oldSet = new HashSet(); + + var oldMap = new Dictionary(); foreach (var c in old) - oldSet.Add($"{c.Path}\n{c.WorkTree}\n{c.Index}"); + oldMap.Add(c.Path, c); foreach (var c in cur) { - if (!oldSet.Contains($"{c.Path}\n{c.WorkTree}\n{c.Index}")) + if (!oldMap.TryGetValue(c.Path, out var o)) + return true; + + if (o.Index != c.Index || o.WorkTree != c.WorkTree) return true; } diff --git a/src/Views/ChangeStatusIcon.cs b/src/Views/ChangeStatusIcon.cs index 5cafb851..c1185174 100644 --- a/src/Views/ChangeStatusIcon.cs +++ b/src/Views/ChangeStatusIcon.cs @@ -48,25 +48,16 @@ namespace SourceGit.Views EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), }, new LinearGradientBrush - { - GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) }, - StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), - EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), - }, - new LinearGradientBrush { GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(47, 185, 47), 0), new GradientStop(Color.FromRgb(75, 189, 75), 1) }, StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), }, + Brushes.OrangeRed, ]; - private static readonly string[] INDICATOR = ["?", "±", "T", "+", "−", "➜", "❏", "U", "★"]; - private static readonly string[] TIPS = ["Unknown", "Modified", "Type Changed", "Added", "Deleted", "Renamed", "Copied", "Unmerged", "Untracked"]; - - private static readonly IBrush BACKGROUND_CONFLICT = Brushes.OrangeRed; - private const string INDICATOR_CONFLICT = "!"; - private const string TIP_CONFLICT = "Conflict"; + private static readonly string[] INDICATOR = ["?", "±", "T", "+", "−", "➜", "❏", "★", "!"]; + private static readonly string[] TIPS = ["Unknown", "Modified", "Type Changed", "Added", "Deleted", "Renamed", "Copied", "Untracked", "Conflict"]; public static readonly StyledProperty IsUnstagedChangeProperty = AvaloniaProperty.Register(nameof(IsUnstagedChange)); @@ -97,16 +88,8 @@ namespace SourceGit.Views string indicator; if (IsUnstagedChange) { - if (Change.IsConflict) - { - background = BACKGROUND_CONFLICT; - indicator = INDICATOR_CONFLICT; - } - else - { - background = BACKGROUNDS[(int)Change.WorkTree]; - indicator = INDICATOR[(int)Change.WorkTree]; - } + background = BACKGROUNDS[(int)Change.WorkTree]; + indicator = INDICATOR[(int)Change.WorkTree]; } else { @@ -143,7 +126,7 @@ namespace SourceGit.Views } if (isUnstaged) - ToolTip.SetTip(this, c.IsConflict ? TIP_CONFLICT : TIPS[(int)c.WorkTree]); + ToolTip.SetTip(this, TIPS[(int)c.WorkTree]); else ToolTip.SetTip(this, TIPS[(int)c.Index]);