mirror of
https://fastgit.cc/github.com/sourcegit-scm/sourcegit
synced 2026-04-21 05:10:25 +08:00
refactor: use a new class Models.ConflictLine for conflict editor instead of Models.TextDiffLine
Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
@@ -2,6 +2,13 @@ using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Models
|
||||
{
|
||||
public enum ConflictPanelType
|
||||
{
|
||||
Ours,
|
||||
Theirs,
|
||||
Result
|
||||
}
|
||||
|
||||
public enum ConflictResolution
|
||||
{
|
||||
None,
|
||||
@@ -11,19 +18,13 @@ namespace SourceGit.Models
|
||||
UseBothTheirsFirst,
|
||||
}
|
||||
|
||||
public enum ConflictMarkerType
|
||||
public enum ConflictLineType
|
||||
{
|
||||
Start, // <<<<<<<
|
||||
Base, // ||||||| (diff3 style)
|
||||
Separator, // =======
|
||||
End, // >>>>>>>
|
||||
}
|
||||
|
||||
public enum ConflictPanelType
|
||||
{
|
||||
Mine,
|
||||
None,
|
||||
Common,
|
||||
Marker,
|
||||
Ours,
|
||||
Theirs,
|
||||
Result
|
||||
}
|
||||
|
||||
public enum ConflictLineState
|
||||
@@ -37,6 +38,28 @@ namespace SourceGit.Models
|
||||
ResolvedBlockEnd,
|
||||
}
|
||||
|
||||
public class ConflictLine
|
||||
{
|
||||
public ConflictLineType Type { get; set; } = ConflictLineType.None;
|
||||
public string Content { get; set; } = string.Empty;
|
||||
public string LineNumber { get; set; } = string.Empty;
|
||||
|
||||
public ConflictLine()
|
||||
{
|
||||
}
|
||||
public ConflictLine(ConflictLineType type, string content)
|
||||
{
|
||||
Type = type;
|
||||
Content = content;
|
||||
}
|
||||
public ConflictLine(ConflictLineType type, string content, int lineNumber)
|
||||
{
|
||||
Type = type;
|
||||
Content = content;
|
||||
LineNumber = lineNumber.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public record ConflictSelectedChunk(
|
||||
double Y,
|
||||
double Height,
|
||||
@@ -45,14 +68,6 @@ namespace SourceGit.Models
|
||||
bool IsResolved
|
||||
);
|
||||
|
||||
public class ConflictMarkerInfo
|
||||
{
|
||||
public int LineNumber { get; set; }
|
||||
public int StartOffset { get; set; }
|
||||
public int EndOffset { get; set; }
|
||||
public ConflictMarkerType Type { get; set; }
|
||||
}
|
||||
|
||||
public class ConflictRegion
|
||||
{
|
||||
public int StartLineInOriginal { get; set; }
|
||||
|
||||
@@ -22,19 +22,19 @@ namespace SourceGit.ViewModels
|
||||
private set => SetProperty(ref _error, value);
|
||||
}
|
||||
|
||||
public List<Models.TextDiffLine> OursDiffLines
|
||||
public List<Models.ConflictLine> OursDiffLines
|
||||
{
|
||||
get => _oursDiffLines;
|
||||
private set => SetProperty(ref _oursDiffLines, value);
|
||||
}
|
||||
|
||||
public List<Models.TextDiffLine> TheirsDiffLines
|
||||
public List<Models.ConflictLine> TheirsDiffLines
|
||||
{
|
||||
get => _theirsDiffLines;
|
||||
private set => SetProperty(ref _theirsDiffLines, value);
|
||||
}
|
||||
|
||||
public List<Models.TextDiffLine> ResultDiffLines
|
||||
public List<Models.ConflictLine> ResultDiffLines
|
||||
{
|
||||
get => _resultDiffLines;
|
||||
private set => SetProperty(ref _resultDiffLines, value);
|
||||
@@ -207,8 +207,8 @@ namespace SourceGit.ViewModels
|
||||
return;
|
||||
|
||||
var lines = content.Split('\n', StringSplitOptions.None);
|
||||
var oursLines = new List<Models.TextDiffLine>();
|
||||
var theirsLines = new List<Models.TextDiffLine>();
|
||||
var oursLines = new List<Models.ConflictLine>();
|
||||
var theirsLines = new List<Models.ConflictLine>();
|
||||
int oursLineNumber = 1;
|
||||
int theirsLineNumber = 1;
|
||||
int i = 0;
|
||||
@@ -225,8 +225,8 @@ namespace SourceGit.ViewModels
|
||||
StartMarker = line,
|
||||
};
|
||||
|
||||
oursLines.Add(new Models.TextDiffLine());
|
||||
theirsLines.Add(new Models.TextDiffLine());
|
||||
oursLines.Add(new());
|
||||
theirsLines.Add(new());
|
||||
i++;
|
||||
|
||||
// Collect ours content
|
||||
@@ -234,7 +234,10 @@ namespace SourceGit.ViewModels
|
||||
!lines[i].StartsWith("|||||||", StringComparison.Ordinal) &&
|
||||
!lines[i].StartsWith("=======", StringComparison.Ordinal))
|
||||
{
|
||||
region.OursContent.Add(lines[i]);
|
||||
line = lines[i];
|
||||
region.OursContent.Add(line);
|
||||
oursLines.Add(new(Models.ConflictLineType.Ours, line, oursLineNumber++));
|
||||
theirsLines.Add(new());
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -249,8 +252,8 @@ namespace SourceGit.ViewModels
|
||||
// Capture separator marker
|
||||
if (i < lines.Length && lines[i].StartsWith("=======", StringComparison.Ordinal))
|
||||
{
|
||||
oursLines.Add(new Models.TextDiffLine());
|
||||
theirsLines.Add(new Models.TextDiffLine());
|
||||
oursLines.Add(new());
|
||||
theirsLines.Add(new());
|
||||
region.SeparatorMarker = lines[i];
|
||||
i++;
|
||||
}
|
||||
@@ -258,27 +261,18 @@ namespace SourceGit.ViewModels
|
||||
// Collect theirs content
|
||||
while (i < lines.Length && !lines[i].StartsWith(">>>>>>>", StringComparison.Ordinal))
|
||||
{
|
||||
region.TheirsContent.Add(lines[i]);
|
||||
line = lines[i];
|
||||
region.TheirsContent.Add(line);
|
||||
oursLines.Add(new());
|
||||
theirsLines.Add(new(Models.ConflictLineType.Theirs, line, theirsLineNumber++));
|
||||
i++;
|
||||
}
|
||||
|
||||
foreach (var mine in region.OursContent)
|
||||
{
|
||||
oursLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Deleted, mine, oursLineNumber++, 0));
|
||||
theirsLines.Add(new Models.TextDiffLine());
|
||||
}
|
||||
|
||||
foreach (var theirs in region.TheirsContent)
|
||||
{
|
||||
oursLines.Add(new Models.TextDiffLine());
|
||||
theirsLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Added, theirs, 0, theirsLineNumber++));
|
||||
}
|
||||
|
||||
// Capture end marker (e.g., ">>>>>>> feature-branch")
|
||||
if (i < lines.Length && lines[i].StartsWith(">>>>>>>", StringComparison.Ordinal))
|
||||
{
|
||||
oursLines.Add(new Models.TextDiffLine());
|
||||
theirsLines.Add(new Models.TextDiffLine());
|
||||
oursLines.Add(new());
|
||||
theirsLines.Add(new());
|
||||
|
||||
region.EndMarker = lines[i];
|
||||
region.EndLineInOriginal = i;
|
||||
@@ -289,8 +283,8 @@ namespace SourceGit.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
oursLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Normal, line, oursLineNumber, oursLineNumber));
|
||||
theirsLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Normal, line, theirsLineNumber, theirsLineNumber));
|
||||
oursLines.Add(new(Models.ConflictLineType.Common, line, oursLineNumber));
|
||||
theirsLines.Add(new(Models.ConflictLineType.Common, line, theirsLineNumber));
|
||||
i++;
|
||||
oursLineNumber++;
|
||||
theirsLineNumber++;
|
||||
@@ -305,7 +299,7 @@ namespace SourceGit.ViewModels
|
||||
|
||||
private void RefreshDisplayData()
|
||||
{
|
||||
var resultLines = new List<Models.TextDiffLine>();
|
||||
var resultLines = new List<Models.ConflictLine>();
|
||||
_lineStates.Clear();
|
||||
|
||||
if (_oursDiffLines == null || _oursDiffLines.Count == 0)
|
||||
@@ -343,14 +337,14 @@ namespace SourceGit.ViewModels
|
||||
int mineCount = currentRegion.OursContent.Count;
|
||||
for (int i = 0; i < mineCount; i++)
|
||||
{
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Deleted, currentRegion.OursContent[i], resultLineNumber, resultLineNumber));
|
||||
resultLines.Add(new(Models.ConflictLineType.Ours, currentRegion.OursContent[i], resultLineNumber));
|
||||
resultLineNumber++;
|
||||
}
|
||||
|
||||
int theirsCount = currentRegion.TheirsContent.Count;
|
||||
for (int i = 0; i < theirsCount; i++)
|
||||
{
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Added, currentRegion.TheirsContent[i], resultLineNumber, resultLineNumber));
|
||||
resultLines.Add(new(Models.ConflictLineType.Theirs, currentRegion.TheirsContent[i], resultLineNumber));
|
||||
resultLineNumber++;
|
||||
}
|
||||
}
|
||||
@@ -359,14 +353,14 @@ namespace SourceGit.ViewModels
|
||||
int theirsCount = currentRegion.TheirsContent.Count;
|
||||
for (int i = 0; i < theirsCount; i++)
|
||||
{
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Added, currentRegion.TheirsContent[i], resultLineNumber, resultLineNumber));
|
||||
resultLines.Add(new(Models.ConflictLineType.Theirs, currentRegion.TheirsContent[i], resultLineNumber));
|
||||
resultLineNumber++;
|
||||
}
|
||||
|
||||
int mineCount = currentRegion.OursContent.Count;
|
||||
for (int i = 0; i < mineCount; i++)
|
||||
{
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Deleted, currentRegion.OursContent[i], resultLineNumber, resultLineNumber));
|
||||
resultLines.Add(new(Models.ConflictLineType.Ours, currentRegion.OursContent[i], resultLineNumber));
|
||||
resultLineNumber++;
|
||||
}
|
||||
}
|
||||
@@ -375,7 +369,7 @@ namespace SourceGit.ViewModels
|
||||
int mineCount = currentRegion.OursContent.Count;
|
||||
for (int i = 0; i < mineCount; i++)
|
||||
{
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Deleted, currentRegion.OursContent[i], resultLineNumber, resultLineNumber));
|
||||
resultLines.Add(new(Models.ConflictLineType.Ours, currentRegion.OursContent[i], resultLineNumber));
|
||||
resultLineNumber++;
|
||||
}
|
||||
}
|
||||
@@ -384,7 +378,7 @@ namespace SourceGit.ViewModels
|
||||
int theirsCount = currentRegion.TheirsContent.Count;
|
||||
for (int i = 0; i < theirsCount; i++)
|
||||
{
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Added, currentRegion.TheirsContent[i], resultLineNumber, resultLineNumber));
|
||||
resultLines.Add(new(Models.ConflictLineType.Theirs, currentRegion.TheirsContent[i], resultLineNumber));
|
||||
resultLineNumber++;
|
||||
}
|
||||
}
|
||||
@@ -393,7 +387,7 @@ namespace SourceGit.ViewModels
|
||||
int added = resultLines.Count - oldLineCount;
|
||||
int padding = regionLines - added;
|
||||
for (int p = 0; p < padding; p++)
|
||||
resultLines.Add(new Models.TextDiffLine());
|
||||
resultLines.Add(new());
|
||||
|
||||
int blockSize = resultLines.Count - oldLineCount - 2;
|
||||
_lineStates.Add(Models.ConflictLineState.ResolvedBlockStart);
|
||||
@@ -403,31 +397,25 @@ namespace SourceGit.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unresolved - show conflict markers with content, aligned with Mine/Theirs
|
||||
// First line: start marker (use real marker from file)
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, currentRegion.StartMarker, 0, 0));
|
||||
resultLines.Add(new(Models.ConflictLineType.Marker, currentRegion.StartMarker));
|
||||
_lineStates.Add(Models.ConflictLineState.ConflictBlockStart);
|
||||
|
||||
// Mine content lines (matches the deleted lines in Ours panel)
|
||||
foreach (var line in currentRegion.OursContent)
|
||||
{
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Deleted, line, 0, resultLineNumber++));
|
||||
resultLines.Add(new(Models.ConflictLineType.Ours, line, resultLineNumber++));
|
||||
_lineStates.Add(Models.ConflictLineState.ConflictBlock);
|
||||
}
|
||||
|
||||
// Separator marker between Mine and Theirs
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, currentRegion.SeparatorMarker, 0, 0));
|
||||
resultLines.Add(new(Models.ConflictLineType.Marker, currentRegion.SeparatorMarker));
|
||||
_lineStates.Add(Models.ConflictLineState.ConflictBlock);
|
||||
|
||||
// Theirs content lines (matches the added lines in Theirs panel)
|
||||
foreach (var line in currentRegion.TheirsContent)
|
||||
{
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Added, line, 0, resultLineNumber++));
|
||||
resultLines.Add(new(Models.ConflictLineType.Theirs, line, resultLineNumber++));
|
||||
_lineStates.Add(Models.ConflictLineState.ConflictBlock);
|
||||
}
|
||||
|
||||
// End marker (use real marker from file)
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, currentRegion.EndMarker, 0, 0));
|
||||
resultLines.Add(new(Models.ConflictLineType.Marker, currentRegion.EndMarker));
|
||||
_lineStates.Add(Models.ConflictLineState.ConflictBlockEnd);
|
||||
}
|
||||
|
||||
@@ -436,20 +424,10 @@ namespace SourceGit.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal line - copy from ours panel
|
||||
var oursLine = _oursDiffLines[currentLine];
|
||||
if (oursLine.Type == Models.TextDiffLineType.Normal)
|
||||
{
|
||||
resultLines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Normal, oursLine.Content, resultLineNumber, resultLineNumber));
|
||||
resultLineNumber++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Empty placeholder line (shouldn't happen outside conflicts, but handle it)
|
||||
resultLines.Add(new Models.TextDiffLine());
|
||||
}
|
||||
|
||||
resultLines.Add(new(oursLine.Type, oursLine.Content, resultLineNumber));
|
||||
_lineStates.Add(Models.ConflictLineState.Normal);
|
||||
resultLineNumber++;
|
||||
currentLine++;
|
||||
}
|
||||
}
|
||||
@@ -473,9 +451,9 @@ namespace SourceGit.ViewModels
|
||||
private string _originalContent = string.Empty;
|
||||
private int _unsolvedCount = 0;
|
||||
private int _diffMaxLineNumber = 0;
|
||||
private List<Models.TextDiffLine> _oursDiffLines = [];
|
||||
private List<Models.TextDiffLine> _theirsDiffLines = [];
|
||||
private List<Models.TextDiffLine> _resultDiffLines = [];
|
||||
private List<Models.ConflictLine> _oursDiffLines = [];
|
||||
private List<Models.ConflictLine> _theirsDiffLines = [];
|
||||
private List<Models.ConflictLine> _resultDiffLines = [];
|
||||
private List<Models.ConflictRegion> _conflictRegions = [];
|
||||
private List<Models.ConflictLineState> _lineStates = [];
|
||||
private Vector _scrollOffset = Vector.Zero;
|
||||
|
||||
@@ -5,8 +5,6 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace SourceGit.ViewModels
|
||||
{
|
||||
public record TextDiffDisplayRange(int Start, int End);
|
||||
|
||||
public record TextDiffSelectedChunk(double Y, double Height, int StartIdx, int EndIdx, bool Combined, bool IsOldSide)
|
||||
{
|
||||
public static bool IsChanged(TextDiffSelectedChunk oldValue, TextDiffSelectedChunk newValue)
|
||||
@@ -43,7 +41,7 @@ namespace SourceGit.ViewModels
|
||||
set => SetProperty(ref _blockNavigation, value);
|
||||
}
|
||||
|
||||
public TextDiffDisplayRange DisplayRange
|
||||
public TextLineRange DisplayRange
|
||||
{
|
||||
get => _displayRange;
|
||||
set => SetProperty(ref _displayRange, value);
|
||||
@@ -161,7 +159,7 @@ namespace SourceGit.ViewModels
|
||||
protected Vector _scrollOffset = Vector.Zero;
|
||||
protected BlockNavigation _blockNavigation = null;
|
||||
|
||||
private TextDiffDisplayRange _displayRange = null;
|
||||
private TextLineRange _displayRange = null;
|
||||
private TextDiffSelectedChunk _selectedChunk = null;
|
||||
}
|
||||
|
||||
|
||||
4
src/ViewModels/TextLineRange.cs
Normal file
4
src/ViewModels/TextLineRange.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
namespace SourceGit.ViewModels
|
||||
{
|
||||
public record TextLineRange(int Start, int End);
|
||||
}
|
||||
@@ -92,18 +92,17 @@
|
||||
FontWeight="Bold"/>
|
||||
</Border>
|
||||
<Grid Grid.Row="1">
|
||||
<v:MergeDiffPresenter x:Name="OursPresenter"
|
||||
PanelType="Mine"
|
||||
DiffLines="{Binding OursDiffLines, Mode=OneWay}"
|
||||
MaxLineNumber="{Binding DiffMaxLineNumber}"
|
||||
FileName="{Binding FilePath}"
|
||||
SelectedChunk="{Binding SelectedChunk}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
|
||||
AddedContentBackground="{DynamicResource Brush.Diff.TheirsBG}"
|
||||
DeletedContentBackground="{DynamicResource Brush.Diff.MineBG}"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"/>
|
||||
<v:MergeConflictTextPresenter x:Name="OursPresenter"
|
||||
PanelType="Ours"
|
||||
Lines="{Binding OursDiffLines, Mode=OneWay}"
|
||||
MaxLineNumber="{Binding DiffMaxLineNumber}"
|
||||
FileName="{Binding FilePath}"
|
||||
SelectedChunk="{Binding SelectedChunk}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
TheirsContentBackground="{DynamicResource Brush.Diff.TheirsBG}"
|
||||
OursContentBackground="{DynamicResource Brush.Diff.MineBG}"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"/>
|
||||
<Border x:Name="MinePopup"
|
||||
IsVisible="False"
|
||||
VerticalAlignment="Top"
|
||||
@@ -132,18 +131,17 @@
|
||||
FontWeight="Bold"/>
|
||||
</Border>
|
||||
<Grid Grid.Row="1">
|
||||
<v:MergeDiffPresenter x:Name="TheirsPresenter"
|
||||
PanelType="Theirs"
|
||||
DiffLines="{Binding TheirsDiffLines, Mode=OneWay}"
|
||||
MaxLineNumber="{Binding DiffMaxLineNumber}"
|
||||
FileName="{Binding FilePath}"
|
||||
SelectedChunk="{Binding SelectedChunk}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
|
||||
AddedContentBackground="{DynamicResource Brush.Diff.TheirsBG}"
|
||||
DeletedContentBackground="{DynamicResource Brush.Diff.MineBG}"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"/>
|
||||
<v:MergeConflictTextPresenter x:Name="TheirsPresenter"
|
||||
PanelType="Theirs"
|
||||
Lines="{Binding TheirsDiffLines, Mode=OneWay}"
|
||||
MaxLineNumber="{Binding DiffMaxLineNumber}"
|
||||
FileName="{Binding FilePath}"
|
||||
SelectedChunk="{Binding SelectedChunk}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
TheirsContentBackground="{DynamicResource Brush.Diff.TheirsBG}"
|
||||
OursContentBackground="{DynamicResource Brush.Diff.MineBG}"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"/>
|
||||
<Border x:Name="TheirsPopup"
|
||||
IsVisible="False"
|
||||
VerticalAlignment="Top"
|
||||
@@ -171,19 +169,17 @@
|
||||
<TextBlock Text="{DynamicResource Text.MergeConflictEditor.Result}" FontWeight="Bold"/>
|
||||
</Border>
|
||||
<Grid Grid.Row="1">
|
||||
<v:MergeDiffPresenter x:Name="ResultPresenter"
|
||||
PanelType="Result"
|
||||
DiffLines="{Binding ResultDiffLines, Mode=OneWay}"
|
||||
MaxLineNumber="{Binding DiffMaxLineNumber}"
|
||||
FileName="{Binding FilePath}"
|
||||
SelectedChunk="{Binding SelectedChunk}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
|
||||
AddedContentBackground="{DynamicResource Brush.Diff.TheirsBG}"
|
||||
DeletedContentBackground="{DynamicResource Brush.Diff.MineBG}"
|
||||
IndicatorBackground="{DynamicResource Brush.Diff.EmptyBG}"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"/>
|
||||
<v:MergeConflictTextPresenter x:Name="ResultPresenter"
|
||||
PanelType="Result"
|
||||
Lines="{Binding ResultDiffLines, Mode=OneWay}"
|
||||
MaxLineNumber="{Binding DiffMaxLineNumber}"
|
||||
FileName="{Binding FilePath}"
|
||||
SelectedChunk="{Binding SelectedChunk}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
TheirsContentBackground="{DynamicResource Brush.Diff.TheirsBG}"
|
||||
OursContentBackground="{DynamicResource Brush.Diff.MineBG}"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"/>
|
||||
<Border x:Name="ResultPopup"
|
||||
IsVisible="False"
|
||||
VerticalAlignment="Top"
|
||||
|
||||
@@ -23,10 +23,181 @@ using AvaloniaEdit.Utils;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class MergeDiffPresenter : TextEditor
|
||||
public class MergeConflictTextPresenter : TextEditor
|
||||
{
|
||||
public class LineNumberMargin : AbstractMargin
|
||||
{
|
||||
public LineNumberMargin(MergeConflictTextPresenter presenter)
|
||||
{
|
||||
_presenter = presenter;
|
||||
Margin = new Thickness(8, 0);
|
||||
ClipToBounds = true;
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
var lines = _presenter.Lines;
|
||||
if (lines == null)
|
||||
return;
|
||||
|
||||
var view = TextView;
|
||||
if (view is not { VisualLinesValid: true })
|
||||
return;
|
||||
|
||||
var typeface = view.CreateTypeface();
|
||||
foreach (var line in view.VisualLines)
|
||||
{
|
||||
if (line.IsDisposed || line.FirstDocumentLine == null || line.FirstDocumentLine.IsDeleted)
|
||||
continue;
|
||||
|
||||
var index = line.FirstDocumentLine.LineNumber;
|
||||
if (index > lines.Count)
|
||||
break;
|
||||
|
||||
var lineNumber = lines[index - 1].LineNumber;
|
||||
if (string.IsNullOrEmpty(lineNumber))
|
||||
continue;
|
||||
|
||||
var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.LineMiddle) - view.VerticalOffset;
|
||||
var txt = new FormattedText(
|
||||
lineNumber,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
_presenter.FontSize,
|
||||
_presenter.Foreground);
|
||||
context.DrawText(txt, new Point(Bounds.Width - txt.Width, y - (txt.Height * 0.5)));
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
var maxLine = _presenter.MaxLineNumber;
|
||||
if (maxLine == 0)
|
||||
return new Size(32, 0);
|
||||
|
||||
var typeface = TextView.CreateTypeface();
|
||||
var test = new FormattedText(
|
||||
$"{maxLine}",
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
_presenter.FontSize,
|
||||
Brushes.White);
|
||||
return new Size(test.Width, 0);
|
||||
}
|
||||
|
||||
private readonly MergeConflictTextPresenter _presenter;
|
||||
}
|
||||
|
||||
public class VerticalSeparatorMargin : AbstractMargin
|
||||
{
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
var pen = new Pen(Brushes.DarkGray);
|
||||
context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height));
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
return new Size(1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class ConflictMarkerTransformer : DocumentColorizingTransformer
|
||||
{
|
||||
public ConflictMarkerTransformer(MergeConflictTextPresenter presenter)
|
||||
{
|
||||
_presenter = presenter;
|
||||
}
|
||||
|
||||
protected override void ColorizeLine(DocumentLine line)
|
||||
{
|
||||
var lines = _presenter.Lines;
|
||||
if (lines == null || line.LineNumber > lines.Count)
|
||||
return;
|
||||
|
||||
var info = lines[line.LineNumber - 1];
|
||||
if (info.Type == Models.ConflictLineType.Marker)
|
||||
{
|
||||
ChangeLinePart(line.Offset, line.EndOffset, element =>
|
||||
{
|
||||
element.TextRunProperties.SetTypeface(new Typeface(_presenter.FontFamily, FontStyle.Italic, FontWeight.Normal));
|
||||
element.TextRunProperties.SetForegroundBrush(Brushes.Gray);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private readonly MergeConflictTextPresenter _presenter;
|
||||
}
|
||||
|
||||
public class LineBackgroundRenderer : IBackgroundRenderer
|
||||
{
|
||||
public KnownLayer Layer => KnownLayer.Background;
|
||||
|
||||
public LineBackgroundRenderer(MergeConflictTextPresenter presenter)
|
||||
{
|
||||
_presenter = presenter;
|
||||
}
|
||||
|
||||
public void Draw(TextView textView, DrawingContext drawingContext)
|
||||
{
|
||||
var lines = _presenter.Lines;
|
||||
if (lines == null || _presenter.Document == null || !textView.VisualLinesValid)
|
||||
return;
|
||||
|
||||
if (_presenter.DataContext is not ViewModels.MergeConflictEditor vm)
|
||||
return;
|
||||
|
||||
var width = textView.Bounds.Width;
|
||||
foreach (var line in textView.VisualLines)
|
||||
{
|
||||
if (line.IsDisposed || line.FirstDocumentLine == null || line.FirstDocumentLine.IsDeleted)
|
||||
continue;
|
||||
|
||||
var index = line.FirstDocumentLine.LineNumber;
|
||||
if (index > lines.Count)
|
||||
break;
|
||||
|
||||
var lineIndex = index - 1;
|
||||
var info = lines[lineIndex];
|
||||
var lineState = vm.GetLineState(lineIndex);
|
||||
|
||||
var startY = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.LineTop) - textView.VerticalOffset;
|
||||
var endY = line.GetTextLineVisualYPosition(line.TextLines[^1], VisualYPosition.LineBottom) - textView.VerticalOffset;
|
||||
var rect = new Rect(0, startY, width, endY - startY);
|
||||
|
||||
if (lineState == Models.ConflictLineState.ConflictBlockStart)
|
||||
drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.Red, 0.6)), new Point(0, startY + 0.5), new Point(width, startY + 0.5));
|
||||
else if (lineState == Models.ConflictLineState.ConflictBlockEnd)
|
||||
drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.Red, 0.6)), new Point(0, endY - 0.5), new Point(width, endY - 0.5));
|
||||
else if (lineState == Models.ConflictLineState.ResolvedBlockStart)
|
||||
drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.Green, 0.6)), new Point(0, startY + 0.5), new Point(width, startY + 0.5));
|
||||
else if (lineState == Models.ConflictLineState.ResolvedBlockEnd)
|
||||
drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.Green, 0.6)), new Point(0, endY - 0.5), new Point(width, endY - 0.5));
|
||||
|
||||
if (lineState >= Models.ConflictLineState.ResolvedBlockStart)
|
||||
drawingContext.DrawRectangle(new SolidColorBrush(Colors.Green, 0.1), null, rect);
|
||||
else if (lineState >= Models.ConflictLineState.ConflictBlockStart)
|
||||
drawingContext.DrawRectangle(new SolidColorBrush(Colors.Red, 0.1), null, rect);
|
||||
|
||||
var bg = info.Type switch
|
||||
{
|
||||
Models.ConflictLineType.Ours => _presenter.OursContentBackground,
|
||||
Models.ConflictLineType.Theirs => _presenter.TheirsContentBackground,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
if (bg != null)
|
||||
drawingContext.DrawRectangle(bg, null, rect);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly MergeConflictTextPresenter _presenter;
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<string> FileNameProperty =
|
||||
AvaloniaProperty.Register<MergeDiffPresenter, string>(nameof(FileName), string.Empty);
|
||||
AvaloniaProperty.Register<MergeConflictTextPresenter, string>(nameof(FileName), string.Empty);
|
||||
|
||||
public string FileName
|
||||
{
|
||||
@@ -35,7 +206,7 @@ namespace SourceGit.Views
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Models.ConflictPanelType> PanelTypeProperty =
|
||||
AvaloniaProperty.Register<MergeDiffPresenter, Models.ConflictPanelType>(nameof(PanelType));
|
||||
AvaloniaProperty.Register<MergeConflictTextPresenter, Models.ConflictPanelType>(nameof(PanelType));
|
||||
|
||||
public Models.ConflictPanelType PanelType
|
||||
{
|
||||
@@ -43,17 +214,17 @@ namespace SourceGit.Views
|
||||
set => SetValue(PanelTypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<List<Models.TextDiffLine>> DiffLinesProperty =
|
||||
AvaloniaProperty.Register<MergeDiffPresenter, List<Models.TextDiffLine>>(nameof(DiffLines));
|
||||
public static readonly StyledProperty<List<Models.ConflictLine>> LinesProperty =
|
||||
AvaloniaProperty.Register<MergeConflictTextPresenter, List<Models.ConflictLine>>(nameof(Lines));
|
||||
|
||||
public List<Models.TextDiffLine> DiffLines
|
||||
public List<Models.ConflictLine> Lines
|
||||
{
|
||||
get => GetValue(DiffLinesProperty);
|
||||
set => SetValue(DiffLinesProperty, value);
|
||||
get => GetValue(LinesProperty);
|
||||
set => SetValue(LinesProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<int> MaxLineNumberProperty =
|
||||
AvaloniaProperty.Register<MergeDiffPresenter, int>(nameof(MaxLineNumber));
|
||||
AvaloniaProperty.Register<MergeConflictTextPresenter, int>(nameof(MaxLineNumber));
|
||||
|
||||
public int MaxLineNumber
|
||||
{
|
||||
@@ -61,44 +232,26 @@ namespace SourceGit.Views
|
||||
set => SetValue(MaxLineNumberProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> EmptyContentBackgroundProperty =
|
||||
AvaloniaProperty.Register<MergeDiffPresenter, IBrush>(nameof(EmptyContentBackground), new SolidColorBrush(Color.FromArgb(60, 0, 0, 0)));
|
||||
public static readonly StyledProperty<IBrush> OursContentBackgroundProperty =
|
||||
AvaloniaProperty.Register<MergeConflictTextPresenter, IBrush>(nameof(OursContentBackground), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0)));
|
||||
|
||||
public IBrush EmptyContentBackground
|
||||
public IBrush OursContentBackground
|
||||
{
|
||||
get => GetValue(EmptyContentBackgroundProperty);
|
||||
set => SetValue(EmptyContentBackgroundProperty, value);
|
||||
get => GetValue(OursContentBackgroundProperty);
|
||||
set => SetValue(OursContentBackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> AddedContentBackgroundProperty =
|
||||
AvaloniaProperty.Register<MergeDiffPresenter, IBrush>(nameof(AddedContentBackground), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0)));
|
||||
public static readonly StyledProperty<IBrush> TheirsContentBackgroundProperty =
|
||||
AvaloniaProperty.Register<MergeConflictTextPresenter, IBrush>(nameof(TheirsContentBackground), new SolidColorBrush(Color.FromArgb(60, 255, 0, 0)));
|
||||
|
||||
public IBrush AddedContentBackground
|
||||
public IBrush TheirsContentBackground
|
||||
{
|
||||
get => GetValue(AddedContentBackgroundProperty);
|
||||
set => SetValue(AddedContentBackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> DeletedContentBackgroundProperty =
|
||||
AvaloniaProperty.Register<MergeDiffPresenter, IBrush>(nameof(DeletedContentBackground), new SolidColorBrush(Color.FromArgb(60, 255, 0, 0)));
|
||||
|
||||
public IBrush DeletedContentBackground
|
||||
{
|
||||
get => GetValue(DeletedContentBackgroundProperty);
|
||||
set => SetValue(DeletedContentBackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> IndicatorBackgroundProperty =
|
||||
AvaloniaProperty.Register<MergeDiffPresenter, IBrush>(nameof(IndicatorBackground), new SolidColorBrush(Color.FromArgb(100, 100, 100, 100)));
|
||||
|
||||
public IBrush IndicatorBackground
|
||||
{
|
||||
get => GetValue(IndicatorBackgroundProperty);
|
||||
set => SetValue(IndicatorBackgroundProperty, value);
|
||||
get => GetValue(TheirsContentBackgroundProperty);
|
||||
set => SetValue(TheirsContentBackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Models.ConflictSelectedChunk> SelectedChunkProperty =
|
||||
AvaloniaProperty.Register<MergeDiffPresenter, Models.ConflictSelectedChunk>(nameof(SelectedChunk));
|
||||
AvaloniaProperty.Register<MergeConflictTextPresenter, Models.ConflictSelectedChunk>(nameof(SelectedChunk));
|
||||
|
||||
public Models.ConflictSelectedChunk SelectedChunk
|
||||
{
|
||||
@@ -106,10 +259,10 @@ namespace SourceGit.Views
|
||||
set => SetValue(SelectedChunkProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<ViewModels.TextDiffDisplayRange> DisplayRangeProperty =
|
||||
AvaloniaProperty.Register<MergeDiffPresenter, ViewModels.TextDiffDisplayRange>(nameof(DisplayRange));
|
||||
public static readonly StyledProperty<ViewModels.TextLineRange> DisplayRangeProperty =
|
||||
AvaloniaProperty.Register<MergeConflictTextPresenter, ViewModels.TextLineRange>(nameof(DisplayRange));
|
||||
|
||||
public ViewModels.TextDiffDisplayRange DisplayRange
|
||||
public ViewModels.TextLineRange DisplayRange
|
||||
{
|
||||
get => GetValue(DisplayRangeProperty);
|
||||
set => SetValue(DisplayRangeProperty, value);
|
||||
@@ -117,7 +270,7 @@ namespace SourceGit.Views
|
||||
|
||||
protected override Type StyleKeyOverride => typeof(TextEditor);
|
||||
|
||||
public MergeDiffPresenter() : base(new TextArea(), new TextDocument())
|
||||
public MergeConflictTextPresenter() : base(new TextArea(), new TextDocument())
|
||||
{
|
||||
IsReadOnly = true;
|
||||
ShowLineNumbers = false;
|
||||
@@ -128,9 +281,9 @@ namespace SourceGit.Views
|
||||
Options.AllowScrollBelowDocument = false;
|
||||
|
||||
TextArea.TextView.Margin = new Thickness(4, 0);
|
||||
TextArea.LeftMargins.Add(new MergeDiffLineNumberMargin(this));
|
||||
TextArea.LeftMargins.Add(new MergeDiffVerticalSeparatorMargin());
|
||||
TextArea.TextView.BackgroundRenderers.Add(new MergeDiffLineBackgroundRenderer(this));
|
||||
TextArea.LeftMargins.Add(new LineNumberMargin(this));
|
||||
TextArea.LeftMargins.Add(new VerticalSeparatorMargin());
|
||||
TextArea.TextView.BackgroundRenderers.Add(new LineBackgroundRenderer(this));
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
@@ -158,7 +311,7 @@ namespace SourceGit.Views
|
||||
TextArea.TextView.PointerMoved += OnTextViewPointerChanged;
|
||||
TextArea.TextView.PointerWheelChanged += OnTextViewPointerWheelChanged;
|
||||
TextArea.TextView.VisualLinesChanged += OnTextViewVisualLinesChanged;
|
||||
TextArea.TextView.LineTransformers.Add(new MergeDiffIndicatorTransformer(this));
|
||||
TextArea.TextView.LineTransformers.Add(new ConflictMarkerTransformer(this));
|
||||
|
||||
OnTextViewVisualLinesChanged(null, null);
|
||||
}
|
||||
@@ -184,7 +337,7 @@ namespace SourceGit.Views
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
||||
if (change.Property == DiffLinesProperty)
|
||||
if (change.Property == LinesProperty)
|
||||
UpdateContent();
|
||||
else if (change.Property == FileNameProperty)
|
||||
Models.TextMateHelper.SetGrammarByFileName(_textMate, FileName);
|
||||
@@ -196,7 +349,7 @@ namespace SourceGit.Views
|
||||
|
||||
private void UpdateContent()
|
||||
{
|
||||
var lines = DiffLines;
|
||||
var lines = Lines;
|
||||
if (lines == null || lines.Count == 0)
|
||||
{
|
||||
Text = string.Empty;
|
||||
@@ -278,7 +431,7 @@ namespace SourceGit.Views
|
||||
return;
|
||||
}
|
||||
|
||||
var lines = DiffLines;
|
||||
var lines = Lines;
|
||||
var start = int.MaxValue;
|
||||
var count = 0;
|
||||
foreach (var line in TextArea.TextView.VisualLines)
|
||||
@@ -295,7 +448,7 @@ namespace SourceGit.Views
|
||||
start = index;
|
||||
}
|
||||
|
||||
SetCurrentValue(DisplayRangeProperty, new ViewModels.TextDiffDisplayRange(start, start + count));
|
||||
SetCurrentValue(DisplayRangeProperty, new ViewModels.TextLineRange(start, start + count));
|
||||
}
|
||||
|
||||
private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e)
|
||||
@@ -317,7 +470,7 @@ namespace SourceGit.Views
|
||||
|
||||
private void UpdateSelectedChunkPosition(ViewModels.MergeConflictEditor vm, double y)
|
||||
{
|
||||
var lines = DiffLines;
|
||||
var lines = Lines;
|
||||
var panel = PanelType;
|
||||
var view = TextArea.TextView;
|
||||
var lineIdx = -1;
|
||||
@@ -380,202 +533,12 @@ namespace SourceGit.Views
|
||||
private ScrollViewer _scrollViewer;
|
||||
}
|
||||
|
||||
public class MergeDiffLineNumberMargin : AbstractMargin
|
||||
{
|
||||
public MergeDiffLineNumberMargin(MergeDiffPresenter presenter)
|
||||
{
|
||||
_presenter = presenter;
|
||||
Margin = new Thickness(8, 0);
|
||||
ClipToBounds = true;
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
var lines = _presenter.DiffLines;
|
||||
if (lines == null)
|
||||
return;
|
||||
|
||||
var view = TextView;
|
||||
if (view is not { VisualLinesValid: true })
|
||||
return;
|
||||
|
||||
var panel = _presenter.PanelType;
|
||||
var typeface = view.CreateTypeface();
|
||||
|
||||
foreach (var line in view.VisualLines)
|
||||
{
|
||||
if (line.IsDisposed || line.FirstDocumentLine == null || line.FirstDocumentLine.IsDeleted)
|
||||
continue;
|
||||
|
||||
var index = line.FirstDocumentLine.LineNumber;
|
||||
if (index > lines.Count)
|
||||
break;
|
||||
|
||||
var info = lines[index - 1];
|
||||
|
||||
string lineNumber = panel switch
|
||||
{
|
||||
Models.ConflictPanelType.Mine => info.OldLine,
|
||||
_ => info.NewLine,
|
||||
};
|
||||
|
||||
if (string.IsNullOrEmpty(lineNumber))
|
||||
continue;
|
||||
|
||||
var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.LineMiddle) - view.VerticalOffset;
|
||||
var txt = new FormattedText(
|
||||
lineNumber,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
_presenter.FontSize,
|
||||
_presenter.Foreground);
|
||||
context.DrawText(txt, new Point(Bounds.Width - txt.Width, y - (txt.Height * 0.5)));
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
var maxLine = _presenter.MaxLineNumber;
|
||||
if (maxLine == 0)
|
||||
return new Size(32, 0);
|
||||
|
||||
var typeface = TextView.CreateTypeface();
|
||||
var test = new FormattedText(
|
||||
$"{maxLine}",
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
_presenter.FontSize,
|
||||
Brushes.White);
|
||||
return new Size(test.Width, 0);
|
||||
}
|
||||
|
||||
private readonly MergeDiffPresenter _presenter;
|
||||
}
|
||||
|
||||
public class MergeDiffVerticalSeparatorMargin : AbstractMargin
|
||||
{
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
var pen = new Pen(Brushes.DarkGray);
|
||||
context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height));
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
return new Size(1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class MergeDiffIndicatorTransformer : DocumentColorizingTransformer
|
||||
{
|
||||
public MergeDiffIndicatorTransformer(MergeDiffPresenter presenter)
|
||||
{
|
||||
_presenter = presenter;
|
||||
}
|
||||
|
||||
protected override void ColorizeLine(DocumentLine line)
|
||||
{
|
||||
var lines = _presenter.DiffLines;
|
||||
if (lines == null || line.LineNumber > lines.Count)
|
||||
return;
|
||||
|
||||
var info = lines[line.LineNumber - 1];
|
||||
if (info.Type == Models.TextDiffLineType.Indicator)
|
||||
{
|
||||
// Make indicator lines (conflict markers) italic and gray
|
||||
ChangeLinePart(line.Offset, line.EndOffset, element =>
|
||||
{
|
||||
element.TextRunProperties.SetTypeface(new Typeface(
|
||||
_presenter.FontFamily,
|
||||
FontStyle.Italic,
|
||||
FontWeight.Normal));
|
||||
element.TextRunProperties.SetForegroundBrush(Brushes.Gray);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private readonly MergeDiffPresenter _presenter;
|
||||
}
|
||||
|
||||
public class MergeDiffLineBackgroundRenderer : IBackgroundRenderer
|
||||
{
|
||||
public KnownLayer Layer => KnownLayer.Background;
|
||||
|
||||
public MergeDiffLineBackgroundRenderer(MergeDiffPresenter presenter)
|
||||
{
|
||||
_presenter = presenter;
|
||||
}
|
||||
|
||||
public void Draw(TextView textView, DrawingContext drawingContext)
|
||||
{
|
||||
var lines = _presenter.DiffLines;
|
||||
if (lines == null || _presenter.Document == null || !textView.VisualLinesValid)
|
||||
return;
|
||||
|
||||
if (_presenter.DataContext is not ViewModels.MergeConflictEditor vm)
|
||||
return;
|
||||
|
||||
var width = textView.Bounds.Width;
|
||||
foreach (var line in textView.VisualLines)
|
||||
{
|
||||
if (line.IsDisposed || line.FirstDocumentLine == null || line.FirstDocumentLine.IsDeleted)
|
||||
continue;
|
||||
|
||||
var index = line.FirstDocumentLine.LineNumber;
|
||||
if (index > lines.Count)
|
||||
break;
|
||||
|
||||
var lineIndex = index - 1;
|
||||
var info = lines[lineIndex];
|
||||
var lineState = vm.GetLineState(lineIndex);
|
||||
|
||||
var startY = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.LineTop) - textView.VerticalOffset;
|
||||
var endY = line.GetTextLineVisualYPosition(line.TextLines[^1], VisualYPosition.LineBottom) - textView.VerticalOffset;
|
||||
var rect = new Rect(0, startY, width, endY - startY);
|
||||
|
||||
if (lineState == Models.ConflictLineState.ConflictBlockStart)
|
||||
drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.Red, 0.6)), new Point(0, startY + 0.5), new Point(width, startY + 0.5));
|
||||
else if (lineState == Models.ConflictLineState.ConflictBlockEnd)
|
||||
drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.Red, 0.6)), new Point(0, endY - 0.5), new Point(width, endY - 0.5));
|
||||
else if (lineState == Models.ConflictLineState.ResolvedBlockStart)
|
||||
drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.Green, 0.6)), new Point(0, startY + 0.5), new Point(width, startY + 0.5));
|
||||
else if (lineState == Models.ConflictLineState.ResolvedBlockEnd)
|
||||
drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.Green, 0.6)), new Point(0, endY - 0.5), new Point(width, endY - 0.5));
|
||||
|
||||
if (lineState >= Models.ConflictLineState.ResolvedBlockStart)
|
||||
drawingContext.DrawRectangle(new SolidColorBrush(Colors.Green, 0.1), null, rect);
|
||||
else if (lineState >= Models.ConflictLineState.ConflictBlockStart)
|
||||
drawingContext.DrawRectangle(new SolidColorBrush(Colors.Red, 0.1), null, rect);
|
||||
|
||||
var bg = GetBrushByLineType(info.Type);
|
||||
if (bg != null)
|
||||
drawingContext.DrawRectangle(bg, null, rect);
|
||||
}
|
||||
}
|
||||
|
||||
private IBrush GetBrushByLineType(Models.TextDiffLineType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
Models.TextDiffLineType.None => _presenter.EmptyContentBackground,
|
||||
Models.TextDiffLineType.Added => _presenter.AddedContentBackground,
|
||||
Models.TextDiffLineType.Deleted => _presenter.DeletedContentBackground,
|
||||
Models.TextDiffLineType.Indicator => _presenter.IndicatorBackground,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
private readonly MergeDiffPresenter _presenter;
|
||||
}
|
||||
|
||||
public class MergeConflictMinimap : Control
|
||||
{
|
||||
public static readonly StyledProperty<ViewModels.TextDiffDisplayRange> DisplayRangeProperty =
|
||||
AvaloniaProperty.Register<MergeConflictMinimap, ViewModels.TextDiffDisplayRange>(nameof(DisplayRange));
|
||||
public static readonly StyledProperty<ViewModels.TextLineRange> DisplayRangeProperty =
|
||||
AvaloniaProperty.Register<MergeConflictMinimap, ViewModels.TextLineRange>(nameof(DisplayRange));
|
||||
|
||||
public ViewModels.TextDiffDisplayRange DisplayRange
|
||||
public ViewModels.TextLineRange DisplayRange
|
||||
{
|
||||
get => GetValue(DisplayRangeProperty);
|
||||
set => SetValue(DisplayRangeProperty, value);
|
||||
@@ -829,9 +792,9 @@ namespace SourceGit.Views
|
||||
return;
|
||||
|
||||
// Get the presenter for bounds checking
|
||||
MergeDiffPresenter presenter = chunk.Panel switch
|
||||
MergeConflictTextPresenter presenter = chunk.Panel switch
|
||||
{
|
||||
Models.ConflictPanelType.Mine => OursPresenter,
|
||||
Models.ConflictPanelType.Ours => OursPresenter,
|
||||
Models.ConflictPanelType.Theirs => TheirsPresenter,
|
||||
Models.ConflictPanelType.Result => ResultPresenter,
|
||||
_ => null
|
||||
@@ -840,7 +803,7 @@ namespace SourceGit.Views
|
||||
// Show the appropriate popup based on panel type and resolved state
|
||||
Border popup = chunk.Panel switch
|
||||
{
|
||||
Models.ConflictPanelType.Mine => MinePopup,
|
||||
Models.ConflictPanelType.Ours => MinePopup,
|
||||
Models.ConflictPanelType.Theirs => TheirsPopup,
|
||||
Models.ConflictPanelType.Result => chunk.IsResolved ? ResultUndoPopup : ResultPopup,
|
||||
_ => null
|
||||
|
||||
@@ -731,7 +731,7 @@ namespace SourceGit.Views
|
||||
start = index;
|
||||
}
|
||||
|
||||
ctx.DisplayRange = new ViewModels.TextDiffDisplayRange(start, start + count);
|
||||
ctx.DisplayRange = new ViewModels.TextLineRange(start, start + count);
|
||||
}
|
||||
|
||||
protected void TrySetChunk(ViewModels.TextDiffSelectedChunk chunk)
|
||||
@@ -1280,10 +1280,10 @@ namespace SourceGit.Views
|
||||
set => SetValue(DeletedLineBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<ViewModels.TextDiffDisplayRange> DisplayRangeProperty =
|
||||
AvaloniaProperty.Register<TextDiffViewMinimap, ViewModels.TextDiffDisplayRange>(nameof(DisplayRange));
|
||||
public static readonly StyledProperty<ViewModels.TextLineRange> DisplayRangeProperty =
|
||||
AvaloniaProperty.Register<TextDiffViewMinimap, ViewModels.TextLineRange>(nameof(DisplayRange));
|
||||
|
||||
public ViewModels.TextDiffDisplayRange DisplayRange
|
||||
public ViewModels.TextLineRange DisplayRange
|
||||
{
|
||||
get => GetValue(DisplayRangeProperty);
|
||||
set => SetValue(DisplayRangeProperty, value);
|
||||
|
||||
Reference in New Issue
Block a user