Replace the Base|Ours|Theirs read-only columns + single-conflict result with a whole-file 3-pane editor: Ours (read-only) | editable Result | Theirs (read-only), reconstructed from the active file's segments so the panes line up on stable text. - IBackgroundRenderer paints each conflict block (unresolved=blood, resolved=green) across all three panes. - Result document edits are gated by an IReadOnlySectionProvider (stable text is read-only; only conflict regions, tracked via TextAnchors, are editable); edits flow back to the owning block. - Between-pane gutters host inline accept controls (>/< ) positioned per conflict; click accepts ours/theirs into the result. - Proportional synced vertical scroll across the panes; file switcher + change-nav arrows (F8 / Shift+F8); active-file 'M conflicts - K resolved' readout. - Merge block tints + AmberBrush tokens; en/de keys for the new labels. Seam unchanged. App builds; Ui.Tests 128, Localization.Tests 16.
167 lines
8.0 KiB
XML
167 lines
8.0 KiB
XML
<Window xmlns="https://github.com/avaloniaui"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:vm="using:ClaudeDo.Ui.ViewModels.Conflicts"
|
|
xmlns:ctl="using:ClaudeDo.Ui.Views.Controls"
|
|
xmlns:ae="clr-namespace:AvaloniaEdit;assembly=AvaloniaEdit"
|
|
xmlns:loc="using:ClaudeDo.Ui.Localization"
|
|
x:DataType="vm:ConflictResolverViewModel"
|
|
x:Class="ClaudeDo.Ui.Views.Conflicts.ConflictResolverView"
|
|
Title="{loc:Tr conflictResolver.windowTitle}"
|
|
Width="1280" Height="820" MinWidth="960" MinHeight="560"
|
|
CanResize="True"
|
|
WindowDecorations="BorderOnly"
|
|
ExtendClientAreaToDecorationsHint="True"
|
|
ExtendClientAreaTitleBarHeightHint="-1"
|
|
WindowStartupLocation="CenterOwner"
|
|
Background="{DynamicResource SurfaceBrush}">
|
|
|
|
<Window.KeyBindings>
|
|
<KeyBinding Gesture="Escape" Command="{Binding AbortCommand}"/>
|
|
<KeyBinding Gesture="F8" Command="{Binding NextCommand}"/>
|
|
<KeyBinding Gesture="Shift+F8" Command="{Binding PreviousCommand}"/>
|
|
</Window.KeyBindings>
|
|
|
|
<Window.Styles>
|
|
<Style Selector="ae|TextEditor">
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
<Setter Property="FontSize" Value="{StaticResource FontSizeMono}" />
|
|
<Setter Property="Background" Value="{DynamicResource Surface2Brush}" />
|
|
<Setter Property="Padding" Value="4,2" />
|
|
<Setter Property="WordWrap" Value="False" />
|
|
</Style>
|
|
<Style Selector="Border.col-head">
|
|
<Setter Property="Padding" Value="8,4" />
|
|
<Setter Property="BorderThickness" Value="0,0,0,1" />
|
|
<Setter Property="BorderBrush" Value="{DynamicResource LineBrush}" />
|
|
<Setter Property="Background" Value="{DynamicResource Surface2Brush}" />
|
|
</Style>
|
|
<Style Selector="Border.pane">
|
|
<Setter Property="BorderBrush" Value="{DynamicResource LineBrush}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="6" />
|
|
<Setter Property="ClipToBounds" Value="True" />
|
|
</Style>
|
|
<!-- Inline accept controls in the between-pane gutters -->
|
|
<Style Selector="Button.accept-gutter">
|
|
<Setter Property="Width" Value="22" />
|
|
<Setter Property="Height" Value="20" />
|
|
<Setter Property="Padding" Value="0" />
|
|
<Setter Property="FontSize" Value="13" />
|
|
<Setter Property="FontWeight" Value="Bold" />
|
|
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
|
<Setter Property="VerticalContentAlignment" Value="Center" />
|
|
<Setter Property="Background" Value="{DynamicResource Surface2Brush}" />
|
|
<Setter Property="BorderBrush" Value="{DynamicResource MergeConflictEdgeBrush}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="4" />
|
|
<Setter Property="Foreground" Value="{DynamicResource TextBrush}" />
|
|
</Style>
|
|
<Style Selector="Button.accept-gutter:pointerover /template/ ContentPresenter">
|
|
<Setter Property="Background" Value="{DynamicResource MergeConflictTintBrush}" />
|
|
</Style>
|
|
</Window.Styles>
|
|
|
|
<ctl:ModalShell Title="{loc:Tr conflictResolver.modalTitle}" CloseCommand="{Binding AbortCommand}">
|
|
<ctl:ModalShell.Footer>
|
|
<Grid ColumnDefinitions="*,Auto">
|
|
<TextBlock Grid.Column="0" Classes="meta" VerticalAlignment="Center"
|
|
Foreground="{DynamicResource BloodBrush}"
|
|
Text="{Binding ContinueHint}"
|
|
IsVisible="{Binding HasBinaryFiles}"/>
|
|
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="8">
|
|
<Button Classes="btn accent" Content="{loc:Tr conflictResolver.continue}"
|
|
Command="{Binding ContinueCommand}" IsEnabled="{Binding CanContinue}"/>
|
|
<Button Classes="btn" Content="{loc:Tr conflictResolver.abort}" Command="{Binding AbortCommand}"/>
|
|
</StackPanel>
|
|
</Grid>
|
|
</ctl:ModalShell.Footer>
|
|
|
|
<Grid Margin="14,10" RowDefinitions="Auto,Auto,Auto,*">
|
|
|
|
<!-- Busy / error -->
|
|
<TextBlock Grid.Row="0" Classes="meta" Margin="0,0,0,6"
|
|
Text="{loc:Tr conflictResolver.loading}" IsVisible="{Binding IsBusy}"/>
|
|
<TextBlock Grid.Row="0" Classes="meta" Foreground="{DynamicResource BloodBrush}"
|
|
Text="{Binding Error}" TextWrapping="Wrap"
|
|
IsVisible="{Binding Error, Converter={x:Static ObjectConverters.IsNotNull}}"/>
|
|
|
|
<!-- Binary-conflict banner -->
|
|
<Border Grid.Row="1" Margin="0,0,0,8" Padding="10,7" CornerRadius="6"
|
|
Background="{DynamicResource ErrorTintBrush}"
|
|
BorderBrush="{DynamicResource BloodBrush}" BorderThickness="1"
|
|
IsVisible="{Binding HasBinaryFiles}">
|
|
<StackPanel Spacing="3">
|
|
<TextBlock Classes="meta" Foreground="{DynamicResource BloodBrush}"
|
|
Text="{loc:Tr conflictResolver.binaryHint}"/>
|
|
<ItemsControl ItemsSource="{Binding BinaryFilePaths}">
|
|
<ItemsControl.ItemTemplate>
|
|
<DataTemplate x:DataType="x:String">
|
|
<TextBlock Classes="path-mono" Text="{Binding}"/>
|
|
</DataTemplate>
|
|
</ItemsControl.ItemTemplate>
|
|
</ItemsControl>
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
<!-- Toolbar: change nav · file switcher · readout -->
|
|
<Grid Grid.Row="2" ColumnDefinitions="Auto,Auto,Auto,*,Auto" Margin="0,0,0,8"
|
|
IsVisible="{Binding HasCurrent}">
|
|
<Button Grid.Column="0" Classes="btn" Content="↑" Margin="0,0,4,0" Padding="10,4"
|
|
ToolTip.Tip="{loc:Tr conflictResolver.prevConflict}"
|
|
Command="{Binding PreviousCommand}"/>
|
|
<Button Grid.Column="1" Classes="btn" Content="↓" Margin="0,0,12,0" Padding="10,4"
|
|
ToolTip.Tip="{loc:Tr conflictResolver.nextConflict}"
|
|
Command="{Binding NextCommand}"/>
|
|
<ComboBox Grid.Column="2" MinWidth="240" MaxWidth="520"
|
|
ItemsSource="{Binding Files}"
|
|
SelectedItem="{Binding ActiveFile, Mode=TwoWay}">
|
|
<ComboBox.ItemTemplate>
|
|
<DataTemplate x:DataType="vm:MergeFile">
|
|
<TextBlock Classes="path-mono" Text="{Binding Path}" TextTrimming="CharacterEllipsis"/>
|
|
</DataTemplate>
|
|
</ComboBox.ItemTemplate>
|
|
</ComboBox>
|
|
<TextBlock Grid.Column="4" Classes="meta" VerticalAlignment="Center"
|
|
Foreground="{DynamicResource TextDimBrush}"
|
|
Text="{Binding PositionText}"/>
|
|
</Grid>
|
|
|
|
<!-- Three panes: Ours | (gutter) | Result | (gutter) | Theirs -->
|
|
<Grid Grid.Row="3" ColumnDefinitions="*,26,*,26,*" IsVisible="{Binding HasCurrent}">
|
|
<Border Grid.Column="0" Classes="pane">
|
|
<DockPanel>
|
|
<Border Classes="col-head" DockPanel.Dock="Top">
|
|
<TextBlock Classes="eyebrow" Text="{loc:Tr conflictResolver.ours}"
|
|
Foreground="{DynamicResource MossBrush}"/>
|
|
</Border>
|
|
<ae:TextEditor Name="OursEditor" IsReadOnly="True" ShowLineNumbers="True"/>
|
|
</DockPanel>
|
|
</Border>
|
|
|
|
<Canvas Grid.Column="1" Name="LeftGutter" Background="Transparent"/>
|
|
|
|
<Border Grid.Column="2" Classes="pane">
|
|
<DockPanel>
|
|
<Border Classes="col-head" DockPanel.Dock="Top">
|
|
<TextBlock Classes="eyebrow" Text="{loc:Tr conflictResolver.result}"/>
|
|
</Border>
|
|
<ae:TextEditor Name="ResultEditor" ShowLineNumbers="True"/>
|
|
</DockPanel>
|
|
</Border>
|
|
|
|
<Canvas Grid.Column="3" Name="RightGutter" Background="Transparent"/>
|
|
|
|
<Border Grid.Column="4" Classes="pane">
|
|
<DockPanel>
|
|
<Border Classes="col-head" DockPanel.Dock="Top">
|
|
<TextBlock Classes="eyebrow" Text="{loc:Tr conflictResolver.theirs}"
|
|
Foreground="{DynamicResource AmberBrush}"/>
|
|
</Border>
|
|
<ae:TextEditor Name="TheirsEditor" IsReadOnly="True" ShowLineNumbers="True"/>
|
|
</DockPanel>
|
|
</Border>
|
|
</Grid>
|
|
</Grid>
|
|
</ctl:ModalShell>
|
|
</Window>
|