From ea9517eef921714d45eeb8fbcd09cf1c6ec9ef25 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 27 Jan 2026 13:34:06 +0800 Subject: [PATCH] code_review: PR #2070 - Remove unused code - Add translations for Chinese (Simplified & Traditional) - UI/UX changes - Fix sync-scroll function sometimes does not work - Re-arrange context menu items for local change Signed-off-by: leo --- src/Models/MergeConflict.cs | 2 - src/Resources/Locales/en_US.axaml | 45 +- src/Resources/Locales/zh_CN.axaml | 21 +- src/Resources/Locales/zh_TW.axaml | 21 +- src/ViewModels/Conflict.cs | 23 +- src/ViewModels/MergeConflictEditor.cs | 187 +------ src/Views/Conflict.axaml | 90 +++- src/Views/Conflict.axaml.cs | 15 +- src/Views/MergeConflictEditor.axaml | 317 ++++++------ src/Views/MergeConflictEditor.axaml.cs | 669 +++++++++---------------- src/Views/WorkingCopy.axaml.cs | 78 +-- 11 files changed, 605 insertions(+), 863 deletions(-) diff --git a/src/Models/MergeConflict.cs b/src/Models/MergeConflict.cs index b2146084..939c761a 100644 --- a/src/Models/MergeConflict.cs +++ b/src/Models/MergeConflict.cs @@ -7,10 +7,8 @@ namespace SourceGit.Models None, UseOurs, UseTheirs, - UseBoth, UseBothMineFirst, UseBothTheirsFirst, - Manual, } public class MergeConflictRegion diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index b9a7fc51..372b0885 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -93,6 +93,8 @@ Reset to Parent Revision Reset to This Revision Generate commit message + Merge (Built-in) + Merge (External) CHANGE DISPLAY MODE Show as File and Dir List Show as Path List @@ -536,6 +538,24 @@ Into: Merge Option: Source: + First Mine, then Theirs + First Theirs, then Mine + USE BOTH + All conflicts resolved + {0} conflict(s) remaining + MINE + Next Conflict + Previous Conflict + RESULT + SAVE & STAGE + THEIRS + Merge Conflicts + Discard unsaved changes? + USE MINE + Resolve current conflict using Mine version + USE THEIRS + Resolve current conflict using Theirs version + UNDO Merge (Multiple) Commit all changes Strategy: @@ -552,8 +572,7 @@ Default Editor (System) Open Data Storage Directory Open File - Open in Merge Tool - Open in Built-in Merge Tool + Open in External Merge Tool Optional. Create New Tab Bookmark @@ -875,24 +894,6 @@ Delete selected {0} tags... Merge ${0}$ into ${1}$... Push ${0}$... - First Mine, then Theirs - First Theirs, then Mine - USE BOTH - All conflicts resolved - {0} conflict(s) remaining - MINE - Next Conflict - Previous Conflict - RESULT - SAVE & STAGE - THEIRS - Merge Conflict - {0} - Discard unsaved changes? - USE MINE - Resolve current conflict using Mine version - USE THEIRS - Resolve current conflict using Theirs version - UNDO Update Submodules All submodules Initialize as needed @@ -936,8 +937,8 @@ You are creating commit on a detached HEAD. Do you want to continue? You have staged {0} file(s) but only {1} file(s) displayed ({2} files are filtered out). Do you want to continue? CONFLICTS DETECTED - OPEN MERGE TOOL - OPEN EXTERNAL MERGETOOL + MERGE + OPEN EXTERNAL MERGETOOL OPEN ALL CONFLICTS IN EXTERNAL MERGETOOL FILE CONFLICTS ARE RESOLVED USE MINE diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index a63adb62..fb271d20 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -97,6 +97,8 @@ 重置文件到上一版本 重置文件到该版本 生成提交信息 + 解决冲突(内部工具) + 解决冲突(外部工具) 切换变更显示模式 文件名+路径列表模式 全路径列表模式 @@ -540,6 +542,22 @@ 目标分支 : 合并方式 : 合并目标 : + 先应用 MINE 后 THEIRS + 先应用 THEIRS 后 MINE + 应用全部 + 所有冲突已解决 + {0} 个冲突未解决 + MINE + 下一个冲突 + 上一个冲突 + 合并结果 + 保存并暂存 + THEIRS + 合并冲突 + 放弃所有更改? + 仅应用 MINE + 仅应用 THEIRS + 撤销更改 合并(多目标) 提交变化 合并策略 : @@ -921,7 +939,8 @@ 您正在向一个游离的 HEAD 提交变更,是否继续提交? 当前有 {0} 个文件在暂存区中,但仅显示了 {1} 个文件({2} 个文件被过滤掉了),是否继续提交? 检测到冲突 - 打开合并工具 + 解决冲突 + 使用外部工具解决冲突 打开合并工具解决冲突 文件冲突已解决 使用 MINE diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index d42b3b51..73e7bc43 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -97,6 +97,8 @@ 重設檔案到上一版本 重設檔案為此版本 產生提交訊息 + 解決衝突 (內建工具) + 解決衝突 (外部工具) 切換變更顯示模式 檔案名稱 + 路徑列表模式 全路徑列表模式 @@ -540,6 +542,22 @@ 目標分支: 合併方式: 合併來源: + 先應用 MINE,再應用 THEIRS + 先應用 THEIRS,再應用 MINE + 應用兩側 + 所有衝突已經解決 + {0} 個衝突尚未解決 + MINE + 下一個衝突 + 上一個衝突 + 合併结果 + 保存並暫存 + THEIRS + 解決衝突 + 放棄所有更改? + 僅應用 MINE + 僅應用 THEIRS + 撤銷更改 合併 (多個來源) 提交變更 合併策略: @@ -921,7 +939,8 @@ 您正在向一个分離狀態的 HEAD 提交變更,您確定要繼續提交嗎? 您已暫存 {0} 個檔案,但只顯示 {1} 個檔案 ({2} 個檔案被篩選器隱藏)。您確定要繼續提交嗎? 偵測到衝突 - 使用外部合併工具開啟 + 解決衝突 + 使用外部工具解決衝突 使用外部合併工具開啟 檔案衝突已解決 使用我方版本 (ours) diff --git a/src/ViewModels/Conflict.cs b/src/ViewModels/Conflict.cs index a057a30f..2f447667 100644 --- a/src/ViewModels/Conflict.cs +++ b/src/ViewModels/Conflict.cs @@ -54,17 +54,12 @@ namespace SourceGit.ViewModels private set; } = false; - public bool CanUseExternalMergeTool + public bool CanMerge { get; private set; } = false; - public bool CanUseBuiltinMergeTool - { - get => CanUseExternalMergeTool; - } - public string FilePath { get => _change.Path; @@ -79,7 +74,7 @@ namespace SourceGit.ViewModels var isSubmodule = repo.Submodules.Find(x => x.Path.Equals(change.Path, StringComparison.Ordinal)) != null; if (!isSubmodule && (_change.ConflictReason is Models.ConflictReason.BothAdded or Models.ConflictReason.BothModified)) { - CanUseExternalMergeTool = true; + CanMerge = true; IsResolved = new Commands.IsConflictResolved(repo.FullPath, change).GetResult(); } @@ -123,14 +118,20 @@ namespace SourceGit.ViewModels await _wc.UseMineAsync([_change]); } - public async Task OpenExternalMergeToolAsync() + public async Task MergeAsync() { - await _wc.UseExternalMergeToolAsync(_change); + if (CanMerge) + { + var ctx = new MergeConflictEditor(_repo, _change.Path); + await ctx.LoadAsync(); + await App.ShowDialog(ctx); + } } - public MergeConflictEditor CreateBuiltinMergeViewModel() + public async Task MergeExternalAsync() { - return new MergeConflictEditor(_repo, _change.Path); + if (CanMerge) + await _wc.UseExternalMergeToolAsync(_change); } private Repository _repo = null; diff --git a/src/ViewModels/MergeConflictEditor.cs b/src/ViewModels/MergeConflictEditor.cs index 65289f51..cc99be22 100644 --- a/src/ViewModels/MergeConflictEditor.cs +++ b/src/ViewModels/MergeConflictEditor.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading.Tasks; using Avalonia; @@ -52,8 +51,6 @@ namespace SourceGit.ViewModels public class MergeConflictEditor : ObservableObject { - public string Title => App.Text("MergeConflictEditor.Title", _filePath); - public string FilePath { get => _filePath; @@ -566,96 +563,6 @@ namespace SourceGit.ViewModels ResultDiffLines = resultLines; } - public void AcceptOurs() - { - if (_conflictRegions.Count == 0) - return; - - bool anyResolved = false; - foreach (var region in _conflictRegions) - { - if (!region.IsResolved) - { - region.ResolvedContent = new List(region.OursContent); - region.IsResolved = true; - region.ResolutionType = Models.ConflictResolution.UseOurs; - anyResolved = true; - } - } - - if (anyResolved) - { - RebuildResultContent(); - BuildAlignedResultPanel(); - UpdateConflictInfo(); - IsModified = true; - } - } - - public void AcceptTheirs() - { - if (_conflictRegions.Count == 0) - return; - - bool anyResolved = false; - foreach (var region in _conflictRegions) - { - if (!region.IsResolved) - { - region.ResolvedContent = new List(region.TheirsContent); - region.IsResolved = true; - region.ResolutionType = Models.ConflictResolution.UseTheirs; - anyResolved = true; - } - } - - if (anyResolved) - { - RebuildResultContent(); - BuildAlignedResultPanel(); - UpdateConflictInfo(); - IsModified = true; - } - } - - public void AcceptCurrentOurs() - { - if (_currentConflictIndex < 0 || _currentConflictIndex >= _conflictRegions.Count) - return; - - var region = _conflictRegions[_currentConflictIndex]; - if (region.IsResolved) - return; - - region.ResolvedContent = new List(region.OursContent); - region.IsResolved = true; - region.ResolutionType = Models.ConflictResolution.UseOurs; - - RebuildResultContent(); - BuildAlignedResultPanel(); - UpdateConflictInfo(); - IsModified = true; - } - - public void AcceptCurrentTheirs() - { - if (_currentConflictIndex < 0 || _currentConflictIndex >= _conflictRegions.Count) - return; - - var region = _conflictRegions[_currentConflictIndex]; - if (region.IsResolved) - return; - - region.ResolvedContent = new List(region.TheirsContent); - region.IsResolved = true; - region.ResolutionType = Models.ConflictResolution.UseTheirs; - - RebuildResultContent(); - BuildAlignedResultPanel(); - UpdateConflictInfo(); - IsModified = true; - } - public IReadOnlyList GetConflictRegions() => _conflictRegions; public void AcceptOursAtIndex(int conflictIndex) @@ -671,10 +578,10 @@ namespace SourceGit.ViewModels region.IsResolved = true; region.ResolutionType = Models.ConflictResolution.UseOurs; + IsModified = true; RebuildResultContent(); BuildAlignedResultPanel(); UpdateConflictInfo(); - IsModified = true; } public void AcceptTheirsAtIndex(int conflictIndex) @@ -690,66 +597,10 @@ namespace SourceGit.ViewModels region.IsResolved = true; region.ResolutionType = Models.ConflictResolution.UseTheirs; + IsModified = true; RebuildResultContent(); BuildAlignedResultPanel(); UpdateConflictInfo(); - IsModified = true; - } - - public void AcceptBothMineFirst() - { - if (_conflictRegions.Count == 0) - return; - - bool anyResolved = false; - foreach (var region in _conflictRegions) - { - if (!region.IsResolved) - { - var combined = new List(region.OursContent); - combined.AddRange(region.TheirsContent); - region.ResolvedContent = combined; - region.IsResolved = true; - region.ResolutionType = Models.ConflictResolution.UseBothMineFirst; - anyResolved = true; - } - } - - if (anyResolved) - { - RebuildResultContent(); - BuildAlignedResultPanel(); - UpdateConflictInfo(); - IsModified = true; - } - } - - public void AcceptBothTheirsFirst() - { - if (_conflictRegions.Count == 0) - return; - - bool anyResolved = false; - foreach (var region in _conflictRegions) - { - if (!region.IsResolved) - { - var combined = new List(region.TheirsContent); - combined.AddRange(region.OursContent); - region.ResolvedContent = combined; - region.IsResolved = true; - region.ResolutionType = Models.ConflictResolution.UseBothTheirsFirst; - anyResolved = true; - } - } - - if (anyResolved) - { - RebuildResultContent(); - BuildAlignedResultPanel(); - UpdateConflictInfo(); - IsModified = true; - } } public void AcceptBothMineFirstAtIndex(int conflictIndex) @@ -767,10 +618,10 @@ namespace SourceGit.ViewModels region.IsResolved = true; region.ResolutionType = Models.ConflictResolution.UseBothMineFirst; + IsModified = true; RebuildResultContent(); BuildAlignedResultPanel(); UpdateConflictInfo(); - IsModified = true; } public void AcceptBothTheirsFirstAtIndex(int conflictIndex) @@ -788,10 +639,10 @@ namespace SourceGit.ViewModels region.IsResolved = true; region.ResolutionType = Models.ConflictResolution.UseBothTheirsFirst; + IsModified = true; RebuildResultContent(); BuildAlignedResultPanel(); UpdateConflictInfo(); - IsModified = true; } public void UndoResolutionAtIndex(int conflictIndex) @@ -807,10 +658,10 @@ namespace SourceGit.ViewModels region.IsResolved = false; region.ResolutionType = Models.ConflictResolution.None; + IsModified = true; RebuildResultContent(); BuildAlignedResultPanel(); UpdateConflictInfo(); - IsModified = true; } public void GotoPrevConflict() @@ -910,7 +761,6 @@ namespace SourceGit.ViewModels if (string.IsNullOrEmpty(_resultContent)) { UnresolvedConflictCount = 0; - _totalConflicts = 0; CurrentConflictIndex = -1; UpdateResolvedRanges(); return; @@ -918,14 +768,16 @@ namespace SourceGit.ViewModels // Count unresolved conflicts in current content var markers = Commands.QueryConflictContent.GetConflictMarkers(_resultContent); - var conflictStarts = markers.Where(m => m.Type == Models.ConflictMarkerType.Start).ToList(); + var conflictStarts = new List(); + foreach (var m in markers) + { + if (m.Type == Models.ConflictMarkerType.Start) + conflictStarts.Add(m); + } int unresolvedCount = conflictStarts.Count; UnresolvedConflictCount = unresolvedCount; - // Total conflicts is the original count (never changes) - _totalConflicts = _conflictRegions.Count; - // Mark which original conflicts are resolved // A conflict is resolved if its start marker no longer exists in _resultContent var currentLines = _resultContent.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); @@ -952,8 +804,20 @@ namespace SourceGit.ViewModels j++; } - if (currentOurs.Count == region.OursContent.Count && - currentOurs.SequenceEqual(region.OursContent)) + if (currentOurs.Count != region.OursContent.Count) + continue; + + var allEquals = true; + for (var k = 0; k < currentOurs.Count; k++) + { + if (!currentOurs[k].Equals(region.OursContent[k], StringComparison.Ordinal)) + { + allEquals = false; + break; + } + } + + if (allEquals) { region.IsResolved = false; break; @@ -1127,7 +991,6 @@ namespace SourceGit.ViewModels private int _currentConflictLine = -1; private int _currentConflictStartLine = -1; private int _currentConflictEndLine = -1; - private int _totalConflicts = 0; private List _oursDiffLines = []; private List _theirsDiffLines = []; private List _resultDiffLines = []; diff --git a/src/Views/Conflict.axaml b/src/Views/Conflict.axaml index 37c8b64c..f9e18a47 100644 --- a/src/Views/Conflict.axaml +++ b/src/Views/Conflict.axaml @@ -124,26 +124,82 @@ - - + diff --git a/src/Views/Conflict.axaml.cs b/src/Views/Conflict.axaml.cs index 1e1e9a47..cdd616f9 100644 --- a/src/Views/Conflict.axaml.cs +++ b/src/Views/Conflict.axaml.cs @@ -37,25 +37,18 @@ namespace SourceGit.Views e.Handled = true; } - private async void OnOpenExternalMergeTool(object _, RoutedEventArgs e) + private async void OnMerge(object _, RoutedEventArgs e) { if (DataContext is ViewModels.Conflict vm) - await vm.OpenExternalMergeToolAsync(); + await vm.MergeAsync(); e.Handled = true; } - private async void OnOpenBuiltinMergeTool(object _, RoutedEventArgs e) + private async void OnMergeExternal(object _, RoutedEventArgs e) { if (DataContext is ViewModels.Conflict vm) - { - var mergeVm = vm.CreateBuiltinMergeViewModel(); - await mergeVm.LoadAsync(); - - var window = TopLevel.GetTopLevel(this) as Window; - var mergeWindow = new MergeConflictEditor { DataContext = mergeVm }; - await mergeWindow.ShowDialog(window); - } + await vm.MergeExternalAsync(); e.Handled = true; } diff --git a/src/Views/MergeConflictEditor.axaml b/src/Views/MergeConflictEditor.axaml index f5b6995e..d23b189e 100644 --- a/src/Views/MergeConflictEditor.axaml +++ b/src/Views/MergeConflictEditor.axaml @@ -9,9 +9,9 @@ x:DataType="vm:MergeConflictEditor" x:Name="ThisControl" Icon="/App.ico" - Title="{Binding Title}" + Title="{DynamicResource Text.MergeConflictEditor.Title}" MinWidth="1024" MinHeight="600"> - + @@ -34,163 +34,76 @@ - + - + + + - - + - + + + + +