diff --git a/src/Models/DiffResult.cs b/src/Models/DiffResult.cs
index 0779029f..500ff549 100644
--- a/src/Models/DiffResult.cs
+++ b/src/Models/DiffResult.cs
@@ -69,7 +69,7 @@ namespace SourceGit.Models
public string Repo { get; set; } = null;
public DiffOption Option { get; set; } = null;
- public TextDiffSelection MakeSelection(int startLine, int endLine, bool isSideBySide, bool isOldSide)
+ public TextDiffSelection MakeSelection(int startLine, int endLine, bool isCombined, bool isOldSide)
{
var rs = new TextDiffSelection();
rs.StartLine = startLine;
@@ -95,7 +95,7 @@ namespace SourceGit.Models
var line = Lines[i];
if (line.Type == TextDiffLineType.Added)
{
- if (!isSideBySide)
+ if (isCombined)
{
rs.HasChanges = true;
break;
@@ -111,7 +111,7 @@ namespace SourceGit.Models
}
else if (line.Type == TextDiffLineType.Deleted)
{
- if (!isSideBySide)
+ if (isCombined)
{
rs.HasChanges = true;
break;
diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index eb5d2122..b5c6a4d3 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -307,9 +307,9 @@
Find next match
Find previous match
Open search panel
- Stage Hunk
- Unstage Hunk
- Discard Hunk
+ Stage
+ Unstage
+ Discard
Initialize Repository
Path:
Invalid repository detected. Run `git init` under this path?
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index ee1a187b..38592803 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -310,9 +310,9 @@
定位到下一个匹配搜索的位置
定位到上一个匹配搜索的位置
打开搜索
- 暂存片断
+ 暂存
移出暂存区
- 丢弃片断
+ 丢弃
初始化新仓库
路径 :
选择目录不是有效的Git仓库。是否需要在此目录执行`git init`操作?
diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml
index 77aa22e7..0c34de95 100644
--- a/src/Resources/Locales/zh_TW.axaml
+++ b/src/Resources/Locales/zh_TW.axaml
@@ -310,9 +310,9 @@
定位到下一個匹配搜尋的位置
定位到上一個匹配搜尋的位置
開啟搜尋
- 暫存片斷
+ 暫存
移出暫存區
- 丟棄片斷
+ 丟棄
初始化新倉庫
路徑 :
選擇目錄不是有效的Git倉庫。是否需要在此目錄執行`git init`操作?
diff --git a/src/ViewModels/TwoSideTextDiff.cs b/src/ViewModels/TwoSideTextDiff.cs
index d4d69059..d5668449 100644
--- a/src/ViewModels/TwoSideTextDiff.cs
+++ b/src/ViewModels/TwoSideTextDiff.cs
@@ -58,11 +58,11 @@ namespace SourceGit.ViewModels
public void ConvertsToCombinedRange(Models.TextDiff combined, ref int startLine, ref int endLine, bool isOldSide)
{
- endLine = Math.Min(endLine, combined.Lines.Count);
+ endLine = Math.Min(endLine, combined.Lines.Count - 1);
var oneSide = isOldSide ? Old : New;
var firstContentLine = -1;
- for (int i = startLine - 1; i < endLine; i++)
+ for (int i = startLine; i <= endLine; i++)
{
var line = oneSide[i];
if (line.Type != Models.TextDiffLineType.None)
@@ -76,7 +76,7 @@ namespace SourceGit.ViewModels
return;
var endContentLine = -1;
- for (int i = Math.Min(endLine - 1, oneSide.Count - 1); i >= startLine - 1; i--)
+ for (int i = Math.Min(endLine, oneSide.Count - 1); i >= startLine; i--)
{
var line = oneSide[i];
if (line.Type != Models.TextDiffLineType.None)
@@ -91,8 +91,8 @@ namespace SourceGit.ViewModels
var firstContent = oneSide[firstContentLine];
var endContent = oneSide[endContentLine];
- startLine = combined.Lines.IndexOf(firstContent) + 1;
- endLine = combined.Lines.IndexOf(endContent) + 1;
+ startLine = combined.Lines.IndexOf(firstContent);
+ endLine = combined.Lines.IndexOf(endContent);
}
private void FillEmptyLines()
diff --git a/src/Views/TextDiffView.axaml b/src/Views/TextDiffView.axaml
index 47589a12..72a952d3 100644
--- a/src/Views/TextDiffView.axaml
+++ b/src/Views/TextDiffView.axaml
@@ -26,7 +26,7 @@
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
- HighlightChunk="{Binding #ThisControl.HighlightChunk, Mode=TwoWay}"/>
+ SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
@@ -46,7 +46,7 @@
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
- HighlightChunk="{Binding #ThisControl.HighlightChunk, Mode=TwoWay}"/>
+ SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
@@ -65,7 +65,7 @@
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
- HighlightChunk="{Binding #ThisControl.HighlightChunk, Mode=TwoWay}"/>
+ SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs
index 4f904f8a..7cbb5327 100644
--- a/src/Views/TextDiffView.axaml.cs
+++ b/src/Views/TextDiffView.axaml.cs
@@ -23,14 +23,16 @@ using AvaloniaEdit.Utils;
namespace SourceGit.Views
{
- public class TextViewHighlightChunk
+ public class TextDiffViewChunk
{
public double Y { get; set; } = 0.0;
public double Height { get; set; } = 0.0;
public int StartIdx { get; set; } = 0;
public int EndIdx { get; set; } = 0;
+ public bool Combined { get; set; } = true;
+ public bool IsOldSide { get; set; } = false;
- public bool ShouldReplace(TextViewHighlightChunk old)
+ public bool ShouldReplace(TextDiffViewChunk old)
{
if (old == null)
return true;
@@ -38,12 +40,203 @@ namespace SourceGit.Views
return Math.Abs(Y - old.Y) > 0.001 ||
Math.Abs(Height - old.Height) > 0.001 ||
StartIdx != old.StartIdx ||
- EndIdx != old.EndIdx;
+ EndIdx != old.EndIdx ||
+ Combined != Combined ||
+ IsOldSide != IsOldSide;
}
}
public class ThemedTextDiffPresenter : TextEditor
{
+ public class VerticalSeperatorMargin : AbstractMargin
+ {
+ public override void Render(DrawingContext context)
+ {
+ var presenter = this.FindAncestorOfType();
+ if (presenter != null)
+ {
+ var pen = new Pen(presenter.LineBrush);
+ 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 LineNumberMargin : AbstractMargin
+ {
+ public LineNumberMargin(bool usePresenter, bool isOld)
+ {
+ _usePresenter = usePresenter;
+ _isOld = isOld;
+ ClipToBounds = true;
+ }
+
+ public override void Render(DrawingContext context)
+ {
+ var presenter = this.FindAncestorOfType();
+ if (presenter == null)
+ return;
+
+ var isOld = _isOld;
+ if (_usePresenter)
+ isOld = presenter.IsOld;
+
+ var lines = presenter.GetLines();
+ var view = TextView;
+ if (view != null && view.VisualLinesValid)
+ {
+ var typeface = view.CreateTypeface();
+ foreach (var line in view.VisualLines)
+ {
+ var index = line.FirstDocumentLine.LineNumber;
+ if (index > lines.Count)
+ break;
+
+ var info = lines[index - 1];
+ var lineNumber = isOld ? info.OldLine : info.NewLine;
+ if (string.IsNullOrEmpty(lineNumber))
+ continue;
+
+ var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop) - 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));
+ }
+ }
+ }
+
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ var presenter = this.FindAncestorOfType();
+ if (presenter == null)
+ return new Size(32, 0);
+
+ var maxLineNumber = presenter.GetMaxLineNumber();
+ var typeface = TextView.CreateTypeface();
+ var test = new FormattedText(
+ $"{maxLineNumber}",
+ CultureInfo.CurrentCulture,
+ FlowDirection.LeftToRight,
+ typeface,
+ presenter.FontSize,
+ Brushes.White);
+ return new Size(test.Width, 0);
+ }
+
+ protected override void OnDataContextChanged(EventArgs e)
+ {
+ base.OnDataContextChanged(e);
+ InvalidateMeasure();
+ }
+
+ private bool _usePresenter = false;
+ private bool _isOld = false;
+ }
+
+ public class LineBackgroundRenderer : IBackgroundRenderer
+ {
+ public KnownLayer Layer => KnownLayer.Background;
+
+ public LineBackgroundRenderer(ThemedTextDiffPresenter presenter)
+ {
+ _presenter = presenter;
+ }
+
+ public void Draw(TextView textView, DrawingContext drawingContext)
+ {
+ if (_presenter.Document == null || !textView.VisualLinesValid)
+ return;
+
+ var lines = _presenter.GetLines();
+ var width = textView.Bounds.Width;
+ foreach (var line in textView.VisualLines)
+ {
+ if (line.FirstDocumentLine == null)
+ continue;
+
+ var index = line.FirstDocumentLine.LineNumber;
+ if (index > lines.Count)
+ break;
+
+ var info = lines[index - 1];
+ var bg = GetBrushByLineType(info.Type);
+ if (bg == null)
+ continue;
+
+ var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop) - textView.VerticalOffset;
+ drawingContext.DrawRectangle(bg, null, new Rect(0, y, width, line.Height));
+ }
+ }
+
+ private IBrush GetBrushByLineType(Models.TextDiffLineType type)
+ {
+ switch (type)
+ {
+ case Models.TextDiffLineType.None:
+ return _presenter.EmptyContentBackground;
+ case Models.TextDiffLineType.Added:
+ return _presenter.AddedContentBackground;
+ case Models.TextDiffLineType.Deleted:
+ return _presenter.DeletedContentBackground;
+ default:
+ return null;
+ }
+ }
+
+ private ThemedTextDiffPresenter _presenter = null;
+ }
+
+ public class LineStyleTransformer : DocumentColorizingTransformer
+ {
+ public LineStyleTransformer(ThemedTextDiffPresenter presenter)
+ {
+ _presenter = presenter;
+ }
+
+ protected override void ColorizeLine(DocumentLine line)
+ {
+ var lines = _presenter.GetLines();
+ var idx = line.LineNumber;
+ if (idx > lines.Count)
+ return;
+
+ var info = lines[idx - 1];
+ if (info.Type == Models.TextDiffLineType.Indicator)
+ {
+ ChangeLinePart(line.Offset, line.EndOffset, v =>
+ {
+ v.TextRunProperties.SetForegroundBrush(_presenter.IndicatorForeground);
+ v.TextRunProperties.SetTypeface(new Typeface(_presenter.FontFamily, FontStyle.Italic));
+ });
+
+ return;
+ }
+
+ if (info.Highlights.Count > 0)
+ {
+ var bg = info.Type == Models.TextDiffLineType.Added ? _presenter.AddedHighlightBrush : _presenter.DeletedHighlightBrush;
+ foreach (var highlight in info.Highlights)
+ {
+ ChangeLinePart(line.Offset + highlight.Start, line.Offset + highlight.Start + highlight.Count, v =>
+ {
+ v.TextRunProperties.SetBackgroundBrush(bg);
+ });
+ }
+ }
+ }
+
+ private readonly ThemedTextDiffPresenter _presenter;
+ }
+
public static readonly StyledProperty FileNameProperty =
AvaloniaProperty.Register(nameof(FileName), string.Empty);
@@ -53,6 +246,15 @@ namespace SourceGit.Views
set => SetValue(FileNameProperty, value);
}
+ public static readonly StyledProperty IsOldProperty =
+ AvaloniaProperty.Register(nameof(IsOld));
+
+ public bool IsOld
+ {
+ get => GetValue(IsOldProperty);
+ set => SetValue(IsOldProperty, value);
+ }
+
public static readonly StyledProperty LineBrushProperty =
AvaloniaProperty.Register(nameof(LineBrush), new SolidColorBrush(Colors.DarkGray));
@@ -134,34 +336,49 @@ namespace SourceGit.Views
set => SetValue(ShowHiddenSymbolsProperty, value);
}
- public static readonly StyledProperty HighlightChunkProperty =
- AvaloniaProperty.Register(nameof(HighlightChunk));
+ public static readonly StyledProperty SelectedChunkProperty =
+ AvaloniaProperty.Register(nameof(SelectedChunk));
- public TextViewHighlightChunk HighlightChunk
+ public TextDiffViewChunk SelectedChunk
{
- get => GetValue(HighlightChunkProperty);
- set => SetValue(HighlightChunkProperty, value);
+ get => GetValue(SelectedChunkProperty);
+ set => SetValue(SelectedChunkProperty, value);
}
protected override Type StyleKeyOverride => typeof(TextEditor);
- protected ThemedTextDiffPresenter(TextArea area, TextDocument doc) : base(area, doc)
+ public ThemedTextDiffPresenter(TextArea area, TextDocument doc) : base(area, doc)
{
IsReadOnly = true;
ShowLineNumbers = false;
BorderThickness = new Thickness(0);
+ _lineStyleTransformer = new LineStyleTransformer(this);
+
TextArea.TextView.Margin = new Thickness(4, 0);
TextArea.TextView.Options.EnableHyperlinks = false;
TextArea.TextView.Options.EnableEmailHyperlinks = false;
+
+ TextArea.TextView.BackgroundRenderers.Add(new LineBackgroundRenderer(this));
+ TextArea.TextView.LineTransformers.Add(_lineStyleTransformer);
+ }
+
+ public virtual List GetLines()
+ {
+ return [];
+ }
+
+ public virtual int GetMaxLineNumber()
+ {
+ return 0;
}
public override void Render(DrawingContext context)
{
base.Render(context);
- var highlightChunk = HighlightChunk;
- if (highlightChunk == null)
+ var chunk = SelectedChunk;
+ if (chunk == null || (!chunk.Combined && chunk.IsOldSide != IsOld))
return;
var view = TextArea.TextView;
@@ -173,7 +390,7 @@ namespace SourceGit.Views
var pen = new Pen(color.ToUInt32());
var x = ((Point)view.TranslatePoint(new Point(0, 0), this)).X;
- var rect = new Rect(x - 4, highlightChunk.Y, view.Bounds.Width + 7, highlightChunk.Height);
+ var rect = new Rect(x - 4, chunk.Y, view.Bounds.Width + 7, chunk.Height);
context.DrawRectangle(brush, null, rect);
context.DrawLine(pen, rect.TopLeft, rect.TopRight);
@@ -219,25 +436,25 @@ namespace SourceGit.Views
{
Models.TextMateHelper.SetThemeByApp(_textMate);
}
- else if (change.Property == HighlightChunkProperty)
+ else if (change.Property == SelectedChunkProperty)
{
InvalidateVisual();
}
}
- protected void TrySetHighlightChunk(TextViewHighlightChunk chunk)
+ protected void TrySetChunk(TextDiffViewChunk chunk)
{
- var old = HighlightChunk;
+ var old = SelectedChunk;
if (chunk == null)
{
if (old != null)
- SetCurrentValue(HighlightChunkProperty, null);
+ SetCurrentValue(SelectedChunkProperty, null);
return;
}
if (chunk.ShouldReplace(old))
- SetCurrentValue(HighlightChunkProperty, chunk);
+ SetCurrentValue(SelectedChunkProperty, chunk);
}
protected (int, int) FindRangeByIndex(List lines, int lineIdx)
@@ -331,208 +548,31 @@ namespace SourceGit.Views
}
private TextMate.Installation _textMate = null;
- protected IVisualLineTransformer _lineStyleTransformer = null;
+ protected LineStyleTransformer _lineStyleTransformer = null;
}
public class CombinedTextDiffPresenter : ThemedTextDiffPresenter
{
- private class LineNumberMargin : AbstractMargin
- {
- public LineNumberMargin(CombinedTextDiffPresenter editor, bool isOldLine)
- {
- _editor = editor;
- _isOldLine = isOldLine;
- ClipToBounds = true;
- }
-
- public override void Render(DrawingContext context)
- {
- if (_editor.DiffData == null)
- return;
-
- var view = TextView;
- if (view != null && view.VisualLinesValid)
- {
- var typeface = view.CreateTypeface();
- foreach (var line in view.VisualLines)
- {
- var index = line.FirstDocumentLine.LineNumber;
- if (index > _editor.DiffData.Lines.Count)
- break;
-
- var info = _editor.DiffData.Lines[index - 1];
- var lineNumber = _isOldLine ? info.OldLine : info.NewLine;
- if (string.IsNullOrEmpty(lineNumber))
- continue;
-
- var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop) - view.VerticalOffset;
- var txt = new FormattedText(
- lineNumber,
- CultureInfo.CurrentCulture,
- FlowDirection.LeftToRight,
- typeface,
- _editor.FontSize,
- _editor.Foreground);
- context.DrawText(txt, new Point(Bounds.Width - txt.Width, y));
- }
- }
- }
-
- protected override Size MeasureOverride(Size availableSize)
- {
- if (_editor.DiffData == null || TextView == null)
- {
- return new Size(32, 0);
- }
-
- var typeface = TextView.CreateTypeface();
- var test = new FormattedText(
- $"{_editor.DiffData.MaxLineNumber}",
- CultureInfo.CurrentCulture,
- FlowDirection.LeftToRight,
- typeface,
- _editor.FontSize,
- Brushes.White);
- return new Size(test.Width, 0);
- }
-
- protected override void OnDataContextChanged(EventArgs e)
- {
- base.OnDataContextChanged(e);
- InvalidateMeasure();
- }
-
- private readonly CombinedTextDiffPresenter _editor;
- private readonly bool _isOldLine;
- }
-
- private class VerticalSeperatorMargin : AbstractMargin
- {
- public VerticalSeperatorMargin(CombinedTextDiffPresenter editor)
- {
- _editor = editor;
- }
-
- public override void Render(DrawingContext context)
- {
- var pen = new Pen(_editor.LineBrush);
- context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height));
- }
-
- protected override Size MeasureOverride(Size availableSize)
- {
- return new Size(1, 0);
- }
-
- private readonly CombinedTextDiffPresenter _editor = null;
- }
-
- private class LineBackgroundRenderer : IBackgroundRenderer
- {
- public KnownLayer Layer => KnownLayer.Background;
-
- public LineBackgroundRenderer(CombinedTextDiffPresenter editor)
- {
- _editor = editor;
- }
-
- public void Draw(TextView textView, DrawingContext drawingContext)
- {
- if (_editor.Document == null || !textView.VisualLinesValid)
- return;
-
- var width = textView.Bounds.Width;
- foreach (var line in textView.VisualLines)
- {
- if (line.FirstDocumentLine == null)
- continue;
-
- var index = line.FirstDocumentLine.LineNumber;
- if (index > _editor.DiffData.Lines.Count)
- break;
-
- var info = _editor.DiffData.Lines[index - 1];
- var bg = GetBrushByLineType(info.Type);
- if (bg == null)
- continue;
-
- var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop) - textView.VerticalOffset;
- drawingContext.DrawRectangle(bg, null, new Rect(0, y, width, line.Height));
- }
- }
-
- private IBrush GetBrushByLineType(Models.TextDiffLineType type)
- {
- switch (type)
- {
- case Models.TextDiffLineType.None:
- return _editor.EmptyContentBackground;
- case Models.TextDiffLineType.Added:
- return _editor.AddedContentBackground;
- case Models.TextDiffLineType.Deleted:
- return _editor.DeletedContentBackground;
- default:
- return null;
- }
- }
-
- private readonly CombinedTextDiffPresenter _editor = null;
- }
-
- private class LineStyleTransformer : DocumentColorizingTransformer
- {
- public LineStyleTransformer(CombinedTextDiffPresenter editor)
- {
- _editor = editor;
- }
-
- protected override void ColorizeLine(DocumentLine line)
- {
- var idx = line.LineNumber;
- if (idx > _editor.DiffData.Lines.Count)
- return;
-
- var info = _editor.DiffData.Lines[idx - 1];
- if (info.Type == Models.TextDiffLineType.Indicator)
- {
- ChangeLinePart(line.Offset, line.EndOffset, v =>
- {
- v.TextRunProperties.SetForegroundBrush(_editor.IndicatorForeground);
- v.TextRunProperties.SetTypeface(new Typeface(_editor.FontFamily, FontStyle.Italic));
- });
-
- return;
- }
-
- if (info.Highlights.Count > 0)
- {
- var bg = info.Type == Models.TextDiffLineType.Added ? _editor.AddedHighlightBrush : _editor.DeletedHighlightBrush;
- foreach (var highlight in info.Highlights)
- {
- ChangeLinePart(line.Offset + highlight.Start, line.Offset + highlight.Start + highlight.Count, v =>
- {
- v.TextRunProperties.SetBackgroundBrush(bg);
- });
- }
- }
- }
-
- private readonly CombinedTextDiffPresenter _editor;
- }
-
- public Models.TextDiff DiffData => DataContext as Models.TextDiff;
-
public CombinedTextDiffPresenter() : base(new TextArea(), new TextDocument())
{
- _lineStyleTransformer = new LineStyleTransformer(this);
+ TextArea.LeftMargins.Add(new LineNumberMargin(false, true) { Margin = new Thickness(8, 0) });
+ TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
+ TextArea.LeftMargins.Add(new LineNumberMargin(false, false) { Margin = new Thickness(8, 0) });
+ TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
+ }
- TextArea.LeftMargins.Add(new LineNumberMargin(this, true) { Margin = new Thickness(8, 0) });
- TextArea.LeftMargins.Add(new VerticalSeperatorMargin(this));
- TextArea.LeftMargins.Add(new LineNumberMargin(this, false) { Margin = new Thickness(8, 0) });
- TextArea.LeftMargins.Add(new VerticalSeperatorMargin(this));
+ public override List GetLines()
+ {
+ if (DataContext is Models.TextDiff diff)
+ return diff.Lines;
+ return [];
+ }
- TextArea.TextView.BackgroundRenderers.Add(new LineBackgroundRenderer(this));
- TextArea.TextView.LineTransformers.Add(_lineStyleTransformer);
+ public override int GetMaxLineNumber()
+ {
+ if (DataContext is Models.TextDiff diff)
+ return diff.MaxLineNumber;
+ return 0;
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
@@ -597,11 +637,6 @@ namespace SourceGit.Views
if (selection.IsEmpty)
return;
- var menu = new ContextMenu();
- var parentView = this.FindAncestorOfType();
- if (parentView != null)
- parentView.FillContextMenuForWorkingCopyChange(menu, selection.StartPosition.Line, selection.EndPosition.Line, false);
-
var copy = new MenuItem();
copy.Header = App.Text("Copy");
copy.Icon = App.CreateMenuIcon("Icons.Copy");
@@ -611,6 +646,7 @@ namespace SourceGit.Views
ev.Handled = true;
};
+ var menu = new ContextMenu();
menu.Items.Add(copy);
TextArea.TextView.OpenContextMenu(menu);
@@ -619,23 +655,65 @@ namespace SourceGit.Views
private void OnTextViewPointerMoved(object sender, PointerEventArgs e)
{
- if (DiffData.Option.WorkingCopyChange == null)
+ var diff = DataContext as Models.TextDiff;
+ if (diff == null || diff.Option.WorkingCopyChange == null)
return;
- if (!string.IsNullOrEmpty(SelectedText))
+ var selection = TextArea.Selection;
+ if (!selection.IsEmpty)
{
- TrySetHighlightChunk(null);
- return;
- }
+ var textView = TextArea.TextView;
+ var startIdx = Math.Min(selection.StartPosition.Line - 1, diff.Lines.Count - 1);
+ var endIdx = Math.Min(selection.EndPosition.Line - 1, diff.Lines.Count - 1);
- if (sender is TextView { VisualLinesValid: true } view)
+ if (startIdx > endIdx)
+ (startIdx, endIdx) = (endIdx, startIdx);
+
+ var hasChanges = false;
+ for (var i = startIdx; i <= endIdx; i++)
+ {
+ var line = diff.Lines[i];
+ if (line.Type == Models.TextDiffLineType.Added || line.Type == Models.TextDiffLineType.Deleted)
+ {
+ hasChanges = true;
+ break;
+ }
+ }
+
+ if (!hasChanges)
+ {
+ TrySetChunk(null);
+ return;
+ }
+
+ var startLine = textView.GetVisualLine(startIdx + 1);
+ var endLine = textView.GetVisualLine(endIdx + 1);
+
+ var rectStartY = startLine != null ?
+ startLine.GetTextLineVisualYPosition(startLine.TextLines[0], VisualYPosition.TextTop) - textView.VerticalOffset :
+ 0;
+ var rectEndY = endLine != null ?
+ endLine.GetTextLineVisualYPosition(endLine.TextLines[^1], VisualYPosition.TextBottom) - textView.VerticalOffset :
+ textView.Bounds.Height;
+
+ TrySetChunk(new TextDiffViewChunk()
+ {
+ Y = rectStartY,
+ Height = rectEndY - rectStartY,
+ StartIdx = startIdx,
+ EndIdx = endIdx,
+ Combined = true,
+ IsOldSide = false,
+ });
+ }
+ else if (sender is TextView { VisualLinesValid: true } view)
{
var y = e.GetPosition(view).Y + view.VerticalOffset;
var lineIdx = -1;
foreach (var line in view.VisualLines)
{
var index = line.FirstDocumentLine.LineNumber;
- if (index > DiffData.Lines.Count)
+ if (index > diff.Lines.Count)
break;
var endY = line.GetTextLineVisualYPosition(line.TextLines[^1], VisualYPosition.TextBottom);
@@ -648,14 +726,14 @@ namespace SourceGit.Views
if (lineIdx == -1)
{
- TrySetHighlightChunk(null);
+ TrySetChunk(null);
return;
}
- var (startIdx, endIdx) = FindRangeByIndex(DiffData.Lines, lineIdx);
+ var (startIdx, endIdx) = FindRangeByIndex(diff.Lines, lineIdx);
if (startIdx == -1)
{
- TrySetHighlightChunk(null);
+ TrySetChunk(null);
return;
}
@@ -669,19 +747,22 @@ namespace SourceGit.Views
endLine.GetTextLineVisualYPosition(endLine.TextLines[^1], VisualYPosition.TextBottom) - view.VerticalOffset:
view.Bounds.Height;
- TrySetHighlightChunk(new TextViewHighlightChunk()
+ TrySetChunk(new TextDiffViewChunk()
{
Y = rectStartY,
Height = rectEndY - rectStartY,
StartIdx = startIdx,
EndIdx = endIdx,
+ Combined = true,
+ IsOldSide = false,
});
}
}
private void OnTextViewPointerWheelChanged(object sender, PointerWheelEventArgs e)
{
- if (DiffData.Option.WorkingCopyChange == null)
+ var diff = DataContext as Models.TextDiff;
+ if (diff == null || diff.Option.WorkingCopyChange == null)
return;
// The offset of TextView has not been updated here. Post a event to next frame.
@@ -691,210 +772,24 @@ namespace SourceGit.Views
public class SingleSideTextDiffPresenter : ThemedTextDiffPresenter
{
- private class LineNumberMargin : AbstractMargin
- {
- public LineNumberMargin(SingleSideTextDiffPresenter editor)
- {
- _editor = editor;
- ClipToBounds = true;
- }
-
- public override void Render(DrawingContext context)
- {
- if (_editor.DiffData == null)
- return;
-
- var view = TextView;
- if (view != null && view.VisualLinesValid)
- {
- var typeface = view.CreateTypeface();
- var infos = _editor.IsOld ? _editor.DiffData.Old : _editor.DiffData.New;
- foreach (var line in view.VisualLines)
- {
- var index = line.FirstDocumentLine.LineNumber;
- if (index > infos.Count)
- break;
-
- var info = infos[index - 1];
- var lineNumber = _editor.IsOld ? info.OldLine : info.NewLine;
- if (string.IsNullOrEmpty(lineNumber))
- continue;
-
- var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop) - view.VerticalOffset;
- var txt = new FormattedText(
- lineNumber,
- CultureInfo.CurrentCulture,
- FlowDirection.LeftToRight,
- typeface,
- _editor.FontSize,
- _editor.Foreground);
- context.DrawText(txt, new Point(Bounds.Width - txt.Width, y));
- }
- }
- }
-
- protected override Size MeasureOverride(Size availableSize)
- {
- if (_editor.DiffData == null || TextView == null)
- {
- return new Size(32, 0);
- }
-
- var typeface = TextView.CreateTypeface();
- var test = new FormattedText(
- $"{_editor.DiffData.MaxLineNumber}",
- CultureInfo.CurrentCulture,
- FlowDirection.LeftToRight,
- typeface,
- _editor.FontSize,
- Brushes.White);
- return new Size(test.Width, 0);
- }
-
- protected override void OnDataContextChanged(EventArgs e)
- {
- base.OnDataContextChanged(e);
- InvalidateMeasure();
- }
-
- private readonly SingleSideTextDiffPresenter _editor;
- }
-
- private class VerticalSeperatorMargin : AbstractMargin
- {
- public VerticalSeperatorMargin(SingleSideTextDiffPresenter editor)
- {
- _editor = editor;
- }
-
- public override void Render(DrawingContext context)
- {
- var pen = new Pen(_editor.LineBrush);
- context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height));
- }
-
- protected override Size MeasureOverride(Size availableSize)
- {
- return new Size(1, 0);
- }
-
- private readonly SingleSideTextDiffPresenter _editor = null;
- }
-
- private class LineBackgroundRenderer : IBackgroundRenderer
- {
- public KnownLayer Layer => KnownLayer.Background;
-
- public LineBackgroundRenderer(SingleSideTextDiffPresenter editor)
- {
- _editor = editor;
- }
-
- public void Draw(TextView textView, DrawingContext drawingContext)
- {
- if (_editor.Document == null || !textView.VisualLinesValid)
- return;
-
- var width = textView.Bounds.Width;
- var infos = _editor.IsOld ? _editor.DiffData.Old : _editor.DiffData.New;
- foreach (var line in textView.VisualLines)
- {
- if (line.FirstDocumentLine == null)
- continue;
-
- var index = line.FirstDocumentLine.LineNumber;
- if (index > infos.Count)
- break;
-
- var info = infos[index - 1];
- var bg = GetBrushByLineType(info.Type);
- if (bg == null)
- continue;
-
- var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop) - textView.VerticalOffset;
- drawingContext.DrawRectangle(bg, null, new Rect(0, y, width, line.Height));
- }
- }
-
- private IBrush GetBrushByLineType(Models.TextDiffLineType type)
- {
- switch (type)
- {
- case Models.TextDiffLineType.None:
- return _editor.EmptyContentBackground;
- case Models.TextDiffLineType.Added:
- return _editor.AddedContentBackground;
- case Models.TextDiffLineType.Deleted:
- return _editor.DeletedContentBackground;
- default:
- return null;
- }
- }
-
- private readonly SingleSideTextDiffPresenter _editor = null;
- }
-
- private class LineStyleTransformer : DocumentColorizingTransformer
- {
- public LineStyleTransformer(SingleSideTextDiffPresenter editor)
- {
- _editor = editor;
- }
-
- protected override void ColorizeLine(DocumentLine line)
- {
- var infos = _editor.IsOld ? _editor.DiffData.Old : _editor.DiffData.New;
- var idx = line.LineNumber;
- if (idx > infos.Count)
- return;
-
- var info = infos[idx - 1];
- if (info.Type == Models.TextDiffLineType.Indicator)
- {
- ChangeLinePart(line.Offset, line.EndOffset, v =>
- {
- v.TextRunProperties.SetForegroundBrush(_editor.IndicatorForeground);
- v.TextRunProperties.SetTypeface(new Typeface(_editor.FontFamily, FontStyle.Italic));
- });
-
- return;
- }
-
- if (info.Highlights.Count > 0)
- {
- var bg = info.Type == Models.TextDiffLineType.Added ? _editor.AddedHighlightBrush : _editor.DeletedHighlightBrush;
- foreach (var highlight in info.Highlights)
- {
- ChangeLinePart(line.Offset + highlight.Start, line.Offset + highlight.Start + highlight.Count, v =>
- {
- v.TextRunProperties.SetBackgroundBrush(bg);
- });
- }
- }
- }
-
- private readonly SingleSideTextDiffPresenter _editor;
- }
-
- public static readonly StyledProperty IsOldProperty =
- AvaloniaProperty.Register(nameof(IsOld));
-
- public bool IsOld
- {
- get => GetValue(IsOldProperty);
- set => SetValue(IsOldProperty, value);
- }
-
- public ViewModels.TwoSideTextDiff DiffData => DataContext as ViewModels.TwoSideTextDiff;
-
public SingleSideTextDiffPresenter() : base(new TextArea(), new TextDocument())
{
- _lineStyleTransformer = new LineStyleTransformer(this);
+ TextArea.LeftMargins.Add(new LineNumberMargin(true, false) { Margin = new Thickness(8, 0) });
+ TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
+ }
- TextArea.LeftMargins.Add(new LineNumberMargin(this) { Margin = new Thickness(8, 0) });
- TextArea.LeftMargins.Add(new VerticalSeperatorMargin(this));
- TextArea.TextView.BackgroundRenderers.Add(new LineBackgroundRenderer(this));
- TextArea.TextView.LineTransformers.Add(_lineStyleTransformer);
+ public override List GetLines()
+ {
+ if (DataContext is ViewModels.TwoSideTextDiff diff)
+ return IsOld ? diff.Old : diff.New;
+ return [];
+ }
+
+ public override int GetMaxLineNumber()
+ {
+ if (DataContext is ViewModels.TwoSideTextDiff diff)
+ return diff.MaxLineNumber;
+ return 0;
}
protected override void OnLoaded(RoutedEventArgs e)
@@ -980,11 +875,6 @@ namespace SourceGit.Views
if (selection.IsEmpty)
return;
- var menu = new ContextMenu();
- var parentView = this.FindAncestorOfType();
- if (parentView != null)
- parentView.FillContextMenuForWorkingCopyChange(menu, selection.StartPosition.Line, selection.EndPosition.Line, IsOld);
-
var copy = new MenuItem();
copy.Header = App.Text("Copy");
copy.Icon = App.CreateMenuIcon("Icons.Copy");
@@ -994,6 +884,7 @@ namespace SourceGit.Views
ev.Handled = true;
};
+ var menu = new ContextMenu();
menu.Items.Add(copy);
TextArea.TextView.OpenContextMenu(menu);
@@ -1002,19 +893,71 @@ namespace SourceGit.Views
private void OnTextViewPointerMoved(object sender, PointerEventArgs e)
{
- if (DiffData.Option.WorkingCopyChange == null)
+ var diff = DataContext as ViewModels.TwoSideTextDiff;
+ if (diff == null || diff.Option.WorkingCopyChange == null)
return;
- if (!string.IsNullOrEmpty(SelectedText))
+ var parent = this.FindAncestorOfType();
+ if (parent == null)
+ return;
+
+ var selection = TextArea.Selection;
+ if (!selection.IsEmpty)
{
- TrySetHighlightChunk(null);
+ var lines = IsOld ? diff.Old : diff.New;
+ var textView = TextArea.TextView;
+ var startIdx = Math.Min(selection.StartPosition.Line - 1, lines.Count - 1);
+ var endIdx = Math.Min(selection.EndPosition.Line - 1, lines.Count - 1);
+
+ if (startIdx > endIdx)
+ (startIdx, endIdx) = (endIdx, startIdx);
+
+ var hasChanges = false;
+ for (var i = startIdx; i <= endIdx; i++)
+ {
+ var line = lines[i];
+ if (line.Type == Models.TextDiffLineType.Added || line.Type == Models.TextDiffLineType.Deleted)
+ {
+ hasChanges = true;
+ break;
+ }
+ }
+
+ if (!hasChanges)
+ {
+ TrySetChunk(null);
+ return;
+ }
+
+ var startLine = textView.GetVisualLine(startIdx + 1);
+ var endLine = textView.GetVisualLine(endIdx + 1);
+
+ var rectStartY = startLine != null ?
+ startLine.GetTextLineVisualYPosition(startLine.TextLines[0], VisualYPosition.TextTop) - textView.VerticalOffset :
+ 0;
+ var rectEndY = endLine != null ?
+ endLine.GetTextLineVisualYPosition(endLine.TextLines[^1], VisualYPosition.TextBottom) - textView.VerticalOffset :
+ textView.Bounds.Height;
+
+ diff.ConvertsToCombinedRange(parent.DataContext as Models.TextDiff, ref startIdx, ref endIdx, IsOld);
+
+ TrySetChunk(new TextDiffViewChunk()
+ {
+ Y = rectStartY,
+ Height = rectEndY - rectStartY,
+ StartIdx = startIdx,
+ EndIdx = endIdx,
+ Combined = false,
+ IsOldSide = IsOld,
+ });
+
return;
}
var parentView = this.FindAncestorOfType();
if (parentView == null || parentView.DataContext == null)
{
- TrySetHighlightChunk(null);
+ TrySetChunk(null);
return;
}
@@ -1023,7 +966,7 @@ namespace SourceGit.Views
{
var y = e.GetPosition(view).Y + view.VerticalOffset;
var lineIdx = -1;
- var lines = IsOld ? DiffData.Old : DiffData.New;
+ var lines = IsOld ? diff.Old : diff.New;
foreach (var line in view.VisualLines)
{
var index = line.FirstDocumentLine.LineNumber;
@@ -1040,14 +983,14 @@ namespace SourceGit.Views
if (lineIdx == -1)
{
- TrySetHighlightChunk(null);
+ TrySetChunk(null);
return;
}
var (startIdx, endIdx) = FindRangeByIndex(lines, lineIdx);
if (startIdx == -1)
{
- TrySetHighlightChunk(null);
+ TrySetChunk(null);
return;
}
@@ -1061,19 +1004,22 @@ namespace SourceGit.Views
endLine.GetTextLineVisualYPosition(endLine.TextLines[^1], VisualYPosition.TextBottom) - view.VerticalOffset :
view.Bounds.Height;
- TrySetHighlightChunk(new TextViewHighlightChunk()
+ TrySetChunk(new TextDiffViewChunk()
{
Y = rectStartY,
Height = rectEndY - rectStartY,
StartIdx = textDiff.Lines.IndexOf(lines[startIdx]),
EndIdx = endIdx == lines.Count - 1 ? textDiff.Lines.Count - 1 : textDiff.Lines.IndexOf(lines[endIdx]),
+ Combined = true,
+ IsOldSide = false,
});
}
}
private void OnTextViewPointerWheelChanged(object sender, PointerWheelEventArgs e)
{
- if (DiffData.Option.WorkingCopyChange == null)
+ var diff = DataContext as ViewModels.TwoSideTextDiff;
+ if (diff == null || diff.Option.WorkingCopyChange == null)
return;
// The offset of TextView has not been updated here. Post a event to next frame.
@@ -1094,13 +1040,13 @@ namespace SourceGit.Views
set => SetValue(UseSideBySideDiffProperty, value);
}
- public static readonly StyledProperty HighlightChunkProperty =
- AvaloniaProperty.Register(nameof(HighlightChunk));
+ public static readonly StyledProperty SelectedChunkProperty =
+ AvaloniaProperty.Register(nameof(SelectedChunk));
- public TextViewHighlightChunk HighlightChunk
+ public TextDiffViewChunk SelectedChunk
{
- get => GetValue(HighlightChunkProperty);
- set => SetValue(HighlightChunkProperty, value);
+ get => GetValue(SelectedChunkProperty);
+ set => SetValue(SelectedChunkProperty, value);
}
public static readonly StyledProperty IsUnstagedChangeProperty =
@@ -1127,16 +1073,18 @@ namespace SourceGit.Views
}
});
- HighlightChunkProperty.Changed.AddClassHandler((v, _) =>
+ SelectedChunkProperty.Changed.AddClassHandler((v, _) =>
{
- if (v.HighlightChunk == null)
+ var chunk = v.SelectedChunk;
+ if (chunk == null)
{
v.Popup.IsVisible = false;
return;
}
- var y = v.HighlightChunk.Y + 16;
- v.Popup.Margin = new Thickness(0, y, 16, 0);
+ var top = chunk.Y + 16;
+ var right = (chunk.Combined || !chunk.IsOldSide) ? 16 : v.Bounds.Width * 0.5f + 16;
+ v.Popup.Margin = new Thickness(0, top, right, 0);
v.Popup.IsVisible = true;
});
}
@@ -1146,250 +1094,12 @@ namespace SourceGit.Views
InitializeComponent();
}
- public void FillContextMenuForWorkingCopyChange(ContextMenu menu, int startLine, int endLine, bool isOldSide)
- {
- var diff = DataContext as Models.TextDiff;
- if (diff == null)
- return;
-
- var change = diff.Option.WorkingCopyChange;
- if (change == null)
- return;
-
- if (startLine > endLine)
- (startLine, endLine) = (endLine, startLine);
-
- if (Editor.Content is ViewModels.TwoSideTextDiff twoSides)
- twoSides.ConvertsToCombinedRange(diff, ref startLine, ref endLine, isOldSide);
-
- var selection = diff.MakeSelection(startLine, endLine, UseSideBySideDiff, isOldSide);
- if (!selection.HasChanges)
- return;
-
- // If all changes has been selected the use method provided by ViewModels.WorkingCopy.
- // Otherwise, use `git apply`
- if (!selection.HasLeftChanges)
- {
- var workcopyView = this.FindAncestorOfType();
- if (workcopyView == null)
- return;
-
- if (diff.Option.IsUnstaged)
- {
- var stage = new MenuItem();
- stage.Header = App.Text("FileCM.StageSelectedLines");
- stage.Icon = App.CreateMenuIcon("Icons.File.Add");
- stage.Click += (_, e) =>
- {
- var workcopy = workcopyView.DataContext as ViewModels.WorkingCopy;
- workcopy?.StageChanges(new List { change });
- e.Handled = true;
- };
-
- var discard = new MenuItem();
- discard.Header = App.Text("FileCM.DiscardSelectedLines");
- discard.Icon = App.CreateMenuIcon("Icons.Undo");
- discard.Click += (_, e) =>
- {
- var workcopy = workcopyView.DataContext as ViewModels.WorkingCopy;
- workcopy?.Discard(new List { change }, true);
- e.Handled = true;
- };
-
- menu.Items.Add(stage);
- menu.Items.Add(discard);
- }
- else
- {
- var unstage = new MenuItem();
- unstage.Header = App.Text("FileCM.UnstageSelectedLines");
- unstage.Icon = App.CreateMenuIcon("Icons.File.Remove");
- unstage.Click += (_, e) =>
- {
- var workcopy = workcopyView.DataContext as ViewModels.WorkingCopy;
- workcopy?.UnstageChanges(new List { change });
- e.Handled = true;
- };
-
- var discard = new MenuItem();
- discard.Header = App.Text("FileCM.DiscardSelectedLines");
- discard.Icon = App.CreateMenuIcon("Icons.Undo");
- discard.Click += (_, e) =>
- {
- var workcopy = workcopyView.DataContext as ViewModels.WorkingCopy;
- workcopy?.Discard(new List { change }, false);
- e.Handled = true;
- };
-
- menu.Items.Add(unstage);
- menu.Items.Add(discard);
- }
- }
- else
- {
- var repoView = this.FindAncestorOfType();
- if (repoView == null)
- return;
-
- if (diff.Option.IsUnstaged)
- {
- var stage = new MenuItem();
- stage.Header = App.Text("FileCM.StageSelectedLines");
- stage.Icon = App.CreateMenuIcon("Icons.File.Add");
- stage.Click += (_, e) =>
- {
- var repo = repoView.DataContext as ViewModels.Repository;
- if (repo == null)
- return;
-
- repo.SetWatcherEnabled(false);
-
- var tmpFile = Path.GetTempFileName();
- if (change.WorkTree == Models.ChangeState.Untracked)
- {
- diff.GenerateNewPatchFromSelection(change, null, selection, false, tmpFile);
- }
- else if (!UseSideBySideDiff)
- {
- var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
- diff.GeneratePatchFromSelection(change, treeGuid, selection, false, tmpFile);
- }
- else
- {
- var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
- diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, false, isOldSide, tmpFile);
- }
-
- new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index").Exec();
- File.Delete(tmpFile);
-
- repo.MarkWorkingCopyDirtyManually();
- repo.SetWatcherEnabled(true);
- e.Handled = true;
- };
-
- var discard = new MenuItem();
- discard.Header = App.Text("FileCM.DiscardSelectedLines");
- discard.Icon = App.CreateMenuIcon("Icons.Undo");
- discard.Click += (_, e) =>
- {
- var repo = repoView.DataContext as ViewModels.Repository;
- if (repo == null)
- return;
-
- repo.SetWatcherEnabled(false);
-
- var tmpFile = Path.GetTempFileName();
- if (change.WorkTree == Models.ChangeState.Untracked)
- {
- diff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile);
- }
- else if (!UseSideBySideDiff)
- {
- var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
- diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
- }
- else
- {
- var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
- diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile);
- }
-
- new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--reverse").Exec();
- File.Delete(tmpFile);
-
- repo.MarkWorkingCopyDirtyManually();
- repo.SetWatcherEnabled(true);
- e.Handled = true;
- };
-
- menu.Items.Add(stage);
- menu.Items.Add(discard);
- }
- else
- {
- var unstage = new MenuItem();
- unstage.Header = App.Text("FileCM.UnstageSelectedLines");
- unstage.Icon = App.CreateMenuIcon("Icons.File.Remove");
- unstage.Click += (_, e) =>
- {
- var repo = repoView.DataContext as ViewModels.Repository;
- if (repo == null)
- return;
-
- repo.SetWatcherEnabled(false);
-
- var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
- var tmpFile = Path.GetTempFileName();
- if (change.Index == Models.ChangeState.Added)
- {
- diff.GenerateNewPatchFromSelection(change, treeGuid, selection, true, tmpFile);
- }
- else if (!UseSideBySideDiff)
- {
- diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
- }
- else
- {
- diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile);
- }
-
- new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index --reverse").Exec();
- File.Delete(tmpFile);
-
- repo.MarkWorkingCopyDirtyManually();
- repo.SetWatcherEnabled(true);
- e.Handled = true;
- };
-
- var discard = new MenuItem();
- discard.Header = App.Text("FileCM.DiscardSelectedLines");
- discard.Icon = App.CreateMenuIcon("Icons.Undo");
- discard.Click += (_, e) =>
- {
- var repo = repoView.DataContext as ViewModels.Repository;
- if (repo == null)
- return;
-
- repo.SetWatcherEnabled(false);
-
- var tmpFile = Path.GetTempFileName();
- var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
- if (change.Index == Models.ChangeState.Added)
- {
- diff.GenerateNewPatchFromSelection(change, treeGuid, selection, true, tmpFile);
- }
- else if (!UseSideBySideDiff)
- {
- diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
- }
- else
- {
- diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile);
- }
-
- new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--index --reverse").Exec();
- File.Delete(tmpFile);
-
- repo.MarkWorkingCopyDirtyManually();
- repo.SetWatcherEnabled(true);
- e.Handled = true;
- };
-
- menu.Items.Add(unstage);
- menu.Items.Add(discard);
- }
- }
-
- menu.Items.Add(new MenuItem() { Header = "-" });
- }
-
protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);
- if (HighlightChunk != null)
- SetCurrentValue(HighlightChunkProperty, null);
+ if (SelectedChunk != null)
+ SetCurrentValue(SelectedChunkProperty, null);
var diff = DataContext as Models.TextDiff;
if (diff == null)
@@ -1411,13 +1121,13 @@ namespace SourceGit.Views
{
base.OnPointerExited(e);
- if (HighlightChunk != null)
- SetCurrentValue(HighlightChunkProperty, null);
+ if (SelectedChunk != null)
+ SetCurrentValue(SelectedChunkProperty, null);
}
private void OnStageChunk(object sender, RoutedEventArgs e)
{
- var chunk = HighlightChunk;
+ var chunk = SelectedChunk;
if (chunk == null)
return;
@@ -1429,7 +1139,7 @@ namespace SourceGit.Views
if (change == null)
return;
- var selection = diff.MakeSelection(chunk.StartIdx + 1, chunk.EndIdx + 1, false, false);
+ var selection = diff.MakeSelection(chunk.StartIdx + 1, chunk.EndIdx + 1, chunk.Combined, chunk.IsOldSide);
if (!selection.HasChanges)
return;
@@ -1459,11 +1169,16 @@ namespace SourceGit.Views
{
diff.GenerateNewPatchFromSelection(change, null, selection, false, tmpFile);
}
- else
+ else if (chunk.Combined)
{
var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
diff.GeneratePatchFromSelection(change, treeGuid, selection, false, tmpFile);
}
+ else
+ {
+ var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
+ diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, false, chunk.IsOldSide, tmpFile);
+ }
new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index").Exec();
File.Delete(tmpFile);
@@ -1475,7 +1190,7 @@ namespace SourceGit.Views
private void OnUnstageChunk(object sender, RoutedEventArgs e)
{
- var chunk = HighlightChunk;
+ var chunk = SelectedChunk;
if (chunk == null)
return;
@@ -1487,7 +1202,7 @@ namespace SourceGit.Views
if (change == null)
return;
- var selection = diff.MakeSelection(chunk.StartIdx + 1, chunk.EndIdx + 1, false, false);
+ var selection = diff.MakeSelection(chunk.StartIdx + 1, chunk.EndIdx + 1, chunk.Combined, chunk.IsOldSide);
if (!selection.HasChanges)
return;
@@ -1518,8 +1233,10 @@ namespace SourceGit.Views
var tmpFile = Path.GetTempFileName();
if (change.Index == Models.ChangeState.Added)
diff.GenerateNewPatchFromSelection(change, treeGuid, selection, true, tmpFile);
- else
+ else if (chunk.Combined)
diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
+ else
+ diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, chunk.IsOldSide, tmpFile);
new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index --reverse").Exec();
File.Delete(tmpFile);
@@ -1531,7 +1248,7 @@ namespace SourceGit.Views
private void OnDiscardChunk(object sender, RoutedEventArgs e)
{
- var chunk = HighlightChunk;
+ var chunk = SelectedChunk;
if (chunk == null)
return;
@@ -1543,7 +1260,7 @@ namespace SourceGit.Views
if (change == null)
return;
- var selection = diff.MakeSelection(chunk.StartIdx + 1, chunk.EndIdx + 1, false, false);
+ var selection = diff.MakeSelection(chunk.StartIdx + 1, chunk.EndIdx + 1, chunk.Combined, chunk.IsOldSide);
if (!selection.HasChanges)
return;
@@ -1571,14 +1288,19 @@ namespace SourceGit.Views
repo.SetWatcherEnabled(false);
var tmpFile = Path.GetTempFileName();
- var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
if (change.Index == Models.ChangeState.Added)
{
- diff.GenerateNewPatchFromSelection(change, treeGuid, selection, true, tmpFile);
- }
+ diff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile);
+ }
+ else if (chunk.Combined)
+ {
+ var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
+ diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
+ }
else
{
- diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
+ var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
+ diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, chunk.IsOldSide, tmpFile);
}
new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", diff.Option.IsUnstaged ? "--reverse" : "--index --reverse").Exec();