feat(merge): diff Merge opens the 3-pane editor + conflict overview ruler
- The Merge button in the Diff window now hands a conflicting merge to the in-app 3-pane editor (MergeModal routes 'conflict' through RequestConflictResolution, the same seam Approve uses) instead of dead-ending on a conflict message. - Add a conflict overview ruler right of the Result pane: a proportional map of every conflict in the file, recolored by resolved state, click a tick to jump — so conflicts are findable in long files without scrolling. - New MergeResolvedEdgeBrush token + conflictMap en/de key. Ui 128 + Loc 16 green.
This commit is contained in:
@@ -149,6 +149,9 @@
|
||||
<Border Classes="col-head" DockPanel.Dock="Top">
|
||||
<TextBlock Classes="eyebrow" Text="{loc:Tr conflictResolver.result}"/>
|
||||
</Border>
|
||||
<Canvas Name="ConflictMap" DockPanel.Dock="Right" Width="13"
|
||||
Background="{DynamicResource Surface2Brush}"
|
||||
ToolTip.Tip="{loc:Tr conflictResolver.conflictMap}"/>
|
||||
<ae:TextEditor Name="ResultEditor" ShowLineNumbers="True"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Shapes;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
using Avalonia.VisualTree;
|
||||
@@ -251,6 +252,7 @@ public partial class ConflictResolverView : Window
|
||||
private void PositionGutters()
|
||||
{
|
||||
ClearGutters();
|
||||
PopulateConflictMap();
|
||||
if (_vm?.ActiveFile is null) return;
|
||||
var tv = ResultEditor.TextArea.TextView;
|
||||
if (!tv.VisualLinesValid)
|
||||
@@ -298,6 +300,47 @@ public partial class ConflictResolverView : Window
|
||||
canvas.Children.Add(b);
|
||||
}
|
||||
|
||||
// ── Conflict overview ruler (right of the result pane) ───────────────────
|
||||
|
||||
// A proportional map of every conflict in the active file so they're findable in
|
||||
// long files without scrolling; ticks recolor by resolved state and jump on click.
|
||||
private void PopulateConflictMap()
|
||||
{
|
||||
ConflictMap.Children.Clear();
|
||||
if (_vm?.ActiveFile is null || _resultRegions.Count == 0) return;
|
||||
var h = ConflictMap.Bounds.Height;
|
||||
if (h <= 1) return;
|
||||
var doc = ResultEditor.Document;
|
||||
var totalLines = Math.Max(1, doc.LineCount);
|
||||
var unresolved = BrushRes("MergeConflictEdgeBrush", Color.Parse("#80C87060"));
|
||||
var resolved = BrushRes("MergeResolvedEdgeBrush", Color.Parse("#806FA86B"));
|
||||
|
||||
foreach (var region in _resultRegions)
|
||||
{
|
||||
var line = doc.GetLineByOffset(region.Start.Offset).LineNumber;
|
||||
var y = (line - 1) / (double)totalLines * h;
|
||||
var tick = new Rectangle
|
||||
{
|
||||
Width = 9,
|
||||
Height = 4,
|
||||
Fill = region.Block.IsResolved ? resolved : unresolved,
|
||||
Cursor = new Avalonia.Input.Cursor(Avalonia.Input.StandardCursorType.Hand),
|
||||
};
|
||||
Canvas.SetLeft(tick, 2);
|
||||
Canvas.SetTop(tick, Math.Min(h - 4, Math.Max(0, y)));
|
||||
var r = region;
|
||||
tick.PointerPressed += (_, _) => JumpToRegion(r);
|
||||
ConflictMap.Children.Add(tick);
|
||||
}
|
||||
}
|
||||
|
||||
private void JumpToRegion(ResultRegion region)
|
||||
{
|
||||
var line = ResultEditor.Document.GetLineByOffset(region.Start.Offset).LineNumber;
|
||||
ResultEditor.ScrollToLine(line);
|
||||
QueueGutters();
|
||||
}
|
||||
|
||||
private static string Tr(string key) => ClaudeDo.Ui.Localization.Loc.T(key);
|
||||
|
||||
// ── Synced vertical scroll across the three panes ─────────────────────────
|
||||
@@ -345,7 +388,7 @@ public partial class ConflictResolverView : Window
|
||||
private void ApplyGrammar(string? path)
|
||||
{
|
||||
if (_registry is null || string.IsNullOrEmpty(path)) return;
|
||||
var ext = Path.GetExtension(path);
|
||||
var ext = System.IO.Path.GetExtension(path);
|
||||
if (string.IsNullOrEmpty(ext)) return;
|
||||
var language = _registry.GetLanguageByExtension(ext);
|
||||
if (language is null) return;
|
||||
|
||||
Reference in New Issue
Block a user