Skip to content

Commit e04e641

Browse files
committed
feat: added popup buttons
1 parent 576fd05 commit e04e641

File tree

3 files changed

+342
-52
lines changed

3 files changed

+342
-52
lines changed

src/ViewModels/MergeConflictEditor.cs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@
1010

1111
namespace SourceGit.ViewModels
1212
{
13+
public enum MergeConflictPanelType
14+
{
15+
Mine,
16+
Theirs,
17+
Result
18+
}
19+
20+
public record MergeConflictSelectedChunk(
21+
double Y,
22+
double Height,
23+
int ConflictIndex,
24+
MergeConflictPanelType Panel
25+
);
26+
1327
// Represents a single conflict region with its original content and panel positions
1428
public class ConflictRegion
1529
{
@@ -163,6 +177,13 @@ public Vector ScrollOffset
163177
set => SetProperty(ref _scrollOffset, value);
164178
}
165179

180+
// Selected chunk for hover-based conflict resolution
181+
public MergeConflictSelectedChunk SelectedChunk
182+
{
183+
get => _selectedChunk;
184+
set => SetProperty(ref _selectedChunk, value);
185+
}
186+
166187
public MergeConflictEditor(Repository repo, string filePath)
167188
{
168189
_repo = repo;
@@ -576,6 +597,44 @@ public void AcceptCurrentTheirs()
576597
IsModified = true;
577598
}
578599

600+
public IReadOnlyList<ConflictRegion> GetConflictRegions() => _conflictRegions;
601+
602+
public void AcceptOursAtIndex(int conflictIndex)
603+
{
604+
if (conflictIndex < 0 || conflictIndex >= _conflictRegions.Count)
605+
return;
606+
607+
var region = _conflictRegions[conflictIndex];
608+
if (region.IsResolved)
609+
return;
610+
611+
region.ResolvedContent = new List<string>(region.OursContent);
612+
region.IsResolved = true;
613+
614+
RebuildResultContent();
615+
BuildAlignedResultPanel();
616+
UpdateConflictInfo();
617+
IsModified = true;
618+
}
619+
620+
public void AcceptTheirsAtIndex(int conflictIndex)
621+
{
622+
if (conflictIndex < 0 || conflictIndex >= _conflictRegions.Count)
623+
return;
624+
625+
var region = _conflictRegions[conflictIndex];
626+
if (region.IsResolved)
627+
return;
628+
629+
region.ResolvedContent = new List<string>(region.TheirsContent);
630+
region.IsResolved = true;
631+
632+
RebuildResultContent();
633+
BuildAlignedResultPanel();
634+
UpdateConflictInfo();
635+
IsModified = true;
636+
}
637+
579638
public void GotoPrevConflict()
580639
{
581640
if (_currentConflictIndex > 0)
@@ -862,5 +921,6 @@ private void UpdateCurrentConflictLine()
862921
private List<ConflictRegion> _conflictRegions = [];
863922
private List<(int Start, int End)> _allConflictRanges = [];
864923
private Vector _scrollOffset = Vector.Zero;
924+
private MergeConflictSelectedChunk _selectedChunk;
865925
}
866926
}

src/Views/MergeConflictEditor.axaml

Lines changed: 119 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,16 @@
4949
ToolTip.Tip="{DynamicResource Text.MergeConflictEditor.PrevConflict}"
5050
Click="OnGotoPrevConflict"
5151
IsEnabled="{Binding HasPrevConflict}">
52-
<Path Width="12" Height="12" Data="{StaticResource Icons.Up}"/>
52+
<Path Width="12" Height="12" Data="{StaticResource Icons.Up}" Margin="0,6,0,0"/>
5353
</Button>
5454
<Button Classes="icon_button"
5555
ToolTip.Tip="{DynamicResource Text.MergeConflictEditor.NextConflict}"
5656
Click="OnGotoNextConflict"
5757
IsEnabled="{Binding HasNextConflict}">
58-
<Path Width="12" Height="12" Data="{StaticResource Icons.Down}"/>
58+
<Path Width="12" Height="12" Data="{StaticResource Icons.Down}" Margin="0,6,0,0"/>
5959
</Button>
60+
<!-- Info Bar -->
61+
<TextBlock Text="{Binding StatusText}" VerticalAlignment="Center"/>
6062

6163
<Rectangle Width="1" Fill="{DynamicResource Brush.Border2}" Margin="4,4"/>
6264

@@ -114,20 +116,39 @@
114116
Foreground="White"
115117
FontWeight="Bold"/>
116118
</Border>
117-
<v:MergeDiffPresenter Grid.Row="1"
118-
x:Name="OursPresenter"
119-
DiffLines="{Binding OursDiffLines, Mode=OneWay}"
120-
MaxLineNumber="{Binding DiffMaxLineNumber}"
121-
FileName="{Binding FilePath}"
122-
IsOldSide="True"
123-
FontFamily="{DynamicResource Fonts.Monospace}"
124-
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
125-
AddedContentBackground="{DynamicResource Brush.Diff.AddedBG}"
126-
DeletedContentBackground="{DynamicResource Brush.Diff.MineBG}"
127-
AddedHighlightBrush="{DynamicResource Brush.Diff.AddedHighlight}"
128-
DeletedHighlightBrush="{DynamicResource Brush.Diff.MineBG}"
129-
BorderThickness="1"
130-
BorderBrush="{DynamicResource Brush.Border2}"/>
119+
<Grid Grid.Row="1">
120+
<v:MergeDiffPresenter x:Name="OursPresenter"
121+
PanelType="Mine"
122+
DiffLines="{Binding OursDiffLines, Mode=OneWay}"
123+
MaxLineNumber="{Binding DiffMaxLineNumber}"
124+
FileName="{Binding FilePath}"
125+
IsOldSide="True"
126+
FontFamily="{DynamicResource Fonts.Monospace}"
127+
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
128+
AddedContentBackground="{DynamicResource Brush.Diff.AddedBG}"
129+
DeletedContentBackground="{DynamicResource Brush.Diff.MineBG}"
130+
AddedHighlightBrush="{DynamicResource Brush.Diff.AddedHighlight}"
131+
DeletedHighlightBrush="{DynamicResource Brush.Diff.MineBG}"
132+
BorderThickness="1"
133+
BorderBrush="{DynamicResource Brush.Border2}"/>
134+
<StackPanel x:Name="MinePopup"
135+
IsVisible="False"
136+
Orientation="Horizontal"
137+
VerticalAlignment="Top"
138+
HorizontalAlignment="Right"
139+
Margin="0,0,8,0">
140+
<Border Background="{DynamicResource Brush.ToolBar}"
141+
BorderBrush="{DynamicResource Brush.Border2}"
142+
BorderThickness="1"
143+
CornerRadius="4"
144+
Padding="4,2"
145+
BoxShadow="0 2 8 0 #40000000">
146+
<Button Classes="flat primary"
147+
Content="{DynamicResource Text.MergeConflictEditor.UseMine}"
148+
Click="OnUseMineFromHover"/>
149+
</Border>
150+
</StackPanel>
151+
</Grid>
131152
</Grid>
132153
</Border>
133154

@@ -139,20 +160,39 @@
139160
Foreground="White"
140161
FontWeight="Bold"/>
141162
</Border>
142-
<v:MergeDiffPresenter Grid.Row="1"
143-
x:Name="TheirsPresenter"
144-
DiffLines="{Binding TheirsDiffLines, Mode=OneWay}"
145-
MaxLineNumber="{Binding DiffMaxLineNumber}"
146-
FileName="{Binding FilePath}"
147-
IsOldSide="False"
148-
FontFamily="{DynamicResource Fonts.Monospace}"
149-
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
150-
AddedContentBackground="{DynamicResource Brush.Diff.TheirsBG}"
151-
DeletedContentBackground="{DynamicResource Brush.Diff.DeletedBG}"
152-
AddedHighlightBrush="{DynamicResource Brush.Diff.TheirsBG}"
153-
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
154-
BorderThickness="1"
155-
BorderBrush="{DynamicResource Brush.Border2}"/>
163+
<Grid Grid.Row="1">
164+
<v:MergeDiffPresenter x:Name="TheirsPresenter"
165+
PanelType="Theirs"
166+
DiffLines="{Binding TheirsDiffLines, Mode=OneWay}"
167+
MaxLineNumber="{Binding DiffMaxLineNumber}"
168+
FileName="{Binding FilePath}"
169+
IsOldSide="False"
170+
FontFamily="{DynamicResource Fonts.Monospace}"
171+
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
172+
AddedContentBackground="{DynamicResource Brush.Diff.TheirsBG}"
173+
DeletedContentBackground="{DynamicResource Brush.Diff.DeletedBG}"
174+
AddedHighlightBrush="{DynamicResource Brush.Diff.TheirsBG}"
175+
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
176+
BorderThickness="1"
177+
BorderBrush="{DynamicResource Brush.Border2}"/>
178+
<StackPanel x:Name="TheirsPopup"
179+
IsVisible="False"
180+
Orientation="Horizontal"
181+
VerticalAlignment="Top"
182+
HorizontalAlignment="Right"
183+
Margin="0,0,8,0">
184+
<Border Background="{DynamicResource Brush.ToolBar}"
185+
BorderBrush="{DynamicResource Brush.Border2}"
186+
BorderThickness="1"
187+
CornerRadius="4"
188+
Padding="4,2"
189+
BoxShadow="0 2 8 0 #40000000">
190+
<Button Classes="flat primary"
191+
Content="{DynamicResource Text.MergeConflictEditor.UseTheirs}"
192+
Click="OnUseTheirsFromHover"/>
193+
</Border>
194+
</StackPanel>
195+
</Grid>
156196
</Grid>
157197
</Border>
158198
</Grid>
@@ -165,32 +205,59 @@
165205
Foreground="{DynamicResource Brush.Window}"
166206
FontWeight="Bold"/>
167207
</Border>
168-
<v:MergeDiffPresenter Grid.Row="1"
169-
x:Name="ResultPresenter"
170-
DiffLines="{Binding ResultDiffLines, Mode=OneWay}"
171-
MaxLineNumber="{Binding DiffMaxLineNumber}"
172-
FileName="{Binding FilePath}"
173-
IsOldSide="False"
174-
IsResultPanel="True"
175-
FontFamily="{DynamicResource Fonts.Monospace}"
176-
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
177-
AddedContentBackground="{DynamicResource Brush.Diff.AddedBG}"
178-
DeletedContentBackground="{DynamicResource Brush.Diff.DeletedBG}"
179-
AddedHighlightBrush="{DynamicResource Brush.Diff.AddedHighlight}"
180-
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
181-
IndicatorBackground="{DynamicResource Brush.Diff.EmptyBG}"
182-
MineContentBackground="{DynamicResource Brush.Diff.MineBG}"
183-
TheirsContentBackground="{DynamicResource Brush.Diff.TheirsBG}"
184-
BorderThickness="1"
185-
BorderBrush="{DynamicResource Brush.Border2}"/>
208+
<Grid Grid.Row="1">
209+
<v:MergeDiffPresenter x:Name="ResultPresenter"
210+
PanelType="Result"
211+
DiffLines="{Binding ResultDiffLines, Mode=OneWay}"
212+
MaxLineNumber="{Binding DiffMaxLineNumber}"
213+
FileName="{Binding FilePath}"
214+
IsOldSide="False"
215+
IsResultPanel="True"
216+
FontFamily="{DynamicResource Fonts.Monospace}"
217+
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
218+
AddedContentBackground="{DynamicResource Brush.Diff.AddedBG}"
219+
DeletedContentBackground="{DynamicResource Brush.Diff.DeletedBG}"
220+
AddedHighlightBrush="{DynamicResource Brush.Diff.AddedHighlight}"
221+
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
222+
IndicatorBackground="{DynamicResource Brush.Diff.EmptyBG}"
223+
MineContentBackground="{DynamicResource Brush.Diff.MineBG}"
224+
TheirsContentBackground="{DynamicResource Brush.Diff.TheirsBG}"
225+
BorderThickness="1"
226+
BorderBrush="{DynamicResource Brush.Border2}"/>
227+
<StackPanel x:Name="ResultPopup"
228+
IsVisible="False"
229+
Orientation="Horizontal"
230+
VerticalAlignment="Top"
231+
HorizontalAlignment="Right"
232+
Margin="0,0,8,0"
233+
Spacing="4">
234+
<Border Background="{DynamicResource Brush.ToolBar}"
235+
BorderBrush="{DynamicResource Brush.Border2}"
236+
BorderThickness="1"
237+
CornerRadius="4"
238+
Padding="4,2"
239+
BoxShadow="0 2 8 0 #40000000">
240+
<Button Classes="flat primary"
241+
Content="{DynamicResource Text.MergeConflictEditor.UseMine}"
242+
Click="OnUseMineFromHover"/>
243+
</Border>
244+
<Border Background="{DynamicResource Brush.ToolBar}"
245+
BorderBrush="{DynamicResource Brush.Border2}"
246+
BorderThickness="1"
247+
CornerRadius="4"
248+
Padding="4,2"
249+
BoxShadow="0 2 8 0 #40000000">
250+
<Button Classes="flat primary"
251+
Content="{DynamicResource Text.MergeConflictEditor.UseTheirs}"
252+
Click="OnUseTheirsFromHover"/>
253+
</Border>
254+
</StackPanel>
255+
</Grid>
186256
</Grid>
187257
</Border>
188258
</Grid>
189259
</Grid>
190260

191-
<!-- Status Bar -->
192-
<Border Grid.Row="3" Padding="8,4" Background="{DynamicResource Brush.ToolBar}" BorderThickness="0,1,0,0" BorderBrush="{DynamicResource Brush.Border2}">
193-
<TextBlock Text="{Binding StatusText}" VerticalAlignment="Center"/>
194-
</Border>
261+
195262
</Grid>
196263
</v:ChromelessWindow>

0 commit comments

Comments
 (0)