Skip to content

Commit 8644075

Browse files
committed
refactor: rewrite text-diff
This commit also contains a feature request #1722 Signed-off-by: leo <[email protected]>
1 parent 5c33198 commit 8644075

File tree

9 files changed

+338
-291
lines changed

9 files changed

+338
-291
lines changed

src/Commands/Diff.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@ public partial class Diff : Command
2020

2121
public Diff(string repo, Models.DiffOption opt, int unified, bool ignoreWhitespace)
2222
{
23-
_result.TextDiff = new Models.TextDiff()
24-
{
25-
Repo = repo,
26-
Option = opt,
27-
};
23+
_result.TextDiff = new Models.TextDiff() { Option = opt };
2824

2925
WorkingDirectory = repo;
3026
Context = repo;

src/Models/DiffResult.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
using System.Collections.Generic;
22
using System.IO;
33
using System.Text.RegularExpressions;
4-
5-
using Avalonia;
64
using Avalonia.Media.Imaging;
75

86
namespace SourceGit.Models
@@ -62,13 +60,10 @@ public bool IsInRange(int idx)
6260
public partial class TextDiff
6361
{
6462
public string File { get; set; } = string.Empty;
63+
public DiffOption Option { get; set; } = null;
6564
public List<TextDiffLine> Lines { get; set; } = new List<TextDiffLine>();
66-
public Vector ScrollOffset { get; set; } = Vector.Zero;
6765
public int MaxLineNumber = 0;
6866

69-
public string Repo { get; set; } = null;
70-
public DiffOption Option { get; set; } = null;
71-
7267
public TextDiffSelection MakeSelection(int startLine, int endLine, bool isCombined, bool isOldSide)
7368
{
7469
var rs = new TextDiffSelection();

src/ViewModels/BlockNavigation.cs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ public BlockNavigation(object context)
5454
Current = -1;
5555

5656
var lines = new List<Models.TextDiffLine>();
57-
if (context is Models.TextDiff combined)
58-
lines = combined.Lines;
57+
if (context is CombinedTextDiff combined)
58+
lines = combined.Data.Lines;
5959
else if (context is TwoSideTextDiff twoSide)
6060
lines = twoSide.Old;
6161

@@ -96,7 +96,10 @@ public BlockNavigation(object context)
9696

9797
public Block GetCurrentBlock()
9898
{
99-
return (_current >= 0 && _current < Blocks.Count) ? Blocks[_current] : null;
99+
if (_current >= 0 && _current < Blocks.Count)
100+
return Blocks[_current];
101+
102+
return Blocks.Count > 0 ? Blocks[0] : null;
100103
}
101104

102105
public Block GotoFirst()
@@ -105,6 +108,7 @@ public Block GotoFirst()
105108
return null;
106109

107110
Current = 0;
111+
OnPropertyChanged(nameof(Indicator));
108112
return Blocks[_current];
109113
}
110114

@@ -117,6 +121,8 @@ public Block GotoPrev()
117121
Current = 0;
118122
else if (_current > 0)
119123
Current = _current - 1;
124+
125+
OnPropertyChanged(nameof(Indicator));
120126
return Blocks[_current];
121127
}
122128

@@ -127,6 +133,8 @@ public Block GotoNext()
127133

128134
if (_current < Blocks.Count - 1)
129135
Current = _current + 1;
136+
137+
OnPropertyChanged(nameof(Indicator));
130138
return Blocks[_current];
131139
}
132140

@@ -136,9 +144,35 @@ public Block GotoLast()
136144
return null;
137145

138146
Current = Blocks.Count - 1;
147+
OnPropertyChanged(nameof(Indicator));
139148
return Blocks[_current];
140149
}
141150

151+
public void AutoUpdate(int start, int end)
152+
{
153+
if (_current >= 0 && _current < Blocks.Count)
154+
{
155+
var block = Blocks[_current];
156+
if ((block.Start >= start && block.Start <= end) ||
157+
(block.End >= start && block.End <= end) ||
158+
(block.Start <= start && block.End >= end))
159+
return;
160+
}
161+
162+
for (var i = 0; i < Blocks.Count; i++)
163+
{
164+
var block = Blocks[i];
165+
if ((block.Start >= start && block.Start <= end) ||
166+
(block.End >= start && block.End <= end) ||
167+
(block.Start <= start && block.End >= end))
168+
{
169+
Current = i;
170+
OnPropertyChanged(nameof(Indicator));
171+
return;
172+
}
173+
}
174+
}
175+
142176
private int _current = -1;
143177
}
144178
}

src/ViewModels/DiffContext.cs

Lines changed: 89 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
using System;
22
using System.IO;
33
using System.Threading.Tasks;
4-
4+
using Avalonia;
55
using Avalonia.Threading;
6-
76
using CommunityToolkit.Mvvm.ComponentModel;
87

98
namespace SourceGit.ViewModels
@@ -24,7 +23,64 @@ public bool IgnoreWhitespace
2423
{
2524
Preferences.Instance.IgnoreWhitespaceChangesInDiff = value;
2625
OnPropertyChanged();
27-
LoadDiffContent();
26+
27+
if (_isTextDiff)
28+
LoadContent();
29+
}
30+
}
31+
}
32+
33+
public bool ShowEntireFile
34+
{
35+
get => Preferences.Instance.UseFullTextDiff;
36+
set
37+
{
38+
if (value != Preferences.Instance.UseFullTextDiff)
39+
{
40+
Preferences.Instance.UseFullTextDiff = value;
41+
OnPropertyChanged();
42+
43+
if (_isTextDiff)
44+
{
45+
if (Content is CombinedTextDiff combined)
46+
combined.ScrollOffset = Vector.Zero;
47+
else if (Content is TwoSideTextDiff twoSide)
48+
twoSide.Data.File = string.Empty;
49+
50+
LoadContent();
51+
}
52+
}
53+
}
54+
}
55+
56+
public bool UseBlockNavigation
57+
{
58+
get => Preferences.Instance.UseBlockNavigationInDiffView;
59+
set
60+
{
61+
if (value != Preferences.Instance.UseBlockNavigationInDiffView)
62+
{
63+
Preferences.Instance.UseBlockNavigationInDiffView = value;
64+
OnPropertyChanged();
65+
66+
if (Content is CombinedTextDiff combined)
67+
combined.BlockNavigation = value ? new BlockNavigation(combined) : null;
68+
else if (Content is TwoSideTextDiff twoSide)
69+
twoSide.BlockNavigation = value ? new BlockNavigation(twoSide) : null;
70+
}
71+
}
72+
}
73+
74+
public bool UseSideBySide
75+
{
76+
get => Preferences.Instance.UseSideBySideDiff;
77+
set
78+
{
79+
if (value != Preferences.Instance.UseSideBySideDiff)
80+
{
81+
Preferences.Instance.UseSideBySideDiff = value;
82+
OnPropertyChanged();
83+
SwitchTextDiffMode();
2884
}
2985
}
3086
}
@@ -72,33 +128,37 @@ public DiffContext(string repo, Models.DiffOption option, DiffContext previous =
72128
else
73129
Title = $"{_option.OrgPath}{_option.Path}";
74130

75-
LoadDiffContent();
76-
}
77-
78-
public void ToggleFullTextDiff()
79-
{
80-
Preferences.Instance.UseFullTextDiff = !Preferences.Instance.UseFullTextDiff;
81-
LoadDiffContent();
131+
LoadContent();
82132
}
83133

84134
public void IncrUnified()
85135
{
86136
UnifiedLines = _unifiedLines + 1;
87-
LoadDiffContent();
137+
LoadContent();
88138
}
89139

90140
public void DecrUnified()
91141
{
92142
UnifiedLines = Math.Max(4, _unifiedLines - 1);
93-
LoadDiffContent();
143+
LoadContent();
94144
}
95145

96146
public void OpenExternalMergeTool()
97147
{
98148
new Commands.DiffTool(_repo, _option).Open();
99149
}
100150

101-
private void LoadDiffContent()
151+
public void SwitchTextDiffMode()
152+
{
153+
var useSideBySide = Preferences.Instance.UseSideBySideDiff;
154+
var hasBlockNavigation = Preferences.Instance.UseBlockNavigationInDiffView;
155+
if (useSideBySide && _content is CombinedTextDiff combined)
156+
Content = new TwoSideTextDiff(combined.Data, hasBlockNavigation);
157+
else if (!useSideBySide && _content is TwoSideTextDiff twoSide)
158+
Content = new CombinedTextDiff(twoSide.Data, hasBlockNavigation);
159+
}
160+
161+
private void LoadContent()
102162
{
103163
if (_option.Path.EndsWith('/'))
104164
{
@@ -228,12 +288,23 @@ private void LoadDiffContent()
228288

229289
Dispatcher.UIThread.Post(() =>
230290
{
231-
if (_content is Models.TextDiff old && rs is Models.TextDiff cur && old.File == cur.File)
232-
cur.ScrollOffset = old.ScrollOffset;
233-
234291
FileModeChange = latest.FileModeChange;
235-
Content = rs;
236-
IsTextDiff = rs is Models.TextDiff;
292+
293+
if (rs is Models.TextDiff cur)
294+
{
295+
IsTextDiff = true;
296+
297+
var hasBlockNavigation = Preferences.Instance.UseBlockNavigationInDiffView;
298+
if (Preferences.Instance.UseSideBySideDiff)
299+
Content = new TwoSideTextDiff(cur, hasBlockNavigation, _content as TwoSideTextDiff);
300+
else
301+
Content = new CombinedTextDiff(cur, hasBlockNavigation, _content as CombinedTextDiff);
302+
}
303+
else
304+
{
305+
IsTextDiff = false;
306+
Content = rs;
307+
}
237308
});
238309
});
239310
}

src/ViewModels/TwoSideTextDiff.cs renamed to src/ViewModels/TextDiffContext.cs

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,70 @@
11
using System;
22
using System.Collections.Generic;
3-
43
using Avalonia;
5-
64
using CommunityToolkit.Mvvm.ComponentModel;
75

86
namespace SourceGit.ViewModels
97
{
8+
public class CombinedTextDiff : ObservableObject
9+
{
10+
public Models.TextDiff Data { get; }
11+
12+
public string File => Data.File;
13+
public int MaxLineNumber => Data.MaxLineNumber;
14+
public bool IsUnstaged => Data.Option.IsUnstaged;
15+
public bool EnableChunkOption => Data.Option.WorkingCopyChange != null;
16+
17+
public Vector ScrollOffset
18+
{
19+
get => _scrollOffset;
20+
set => SetProperty(ref _scrollOffset, value);
21+
}
22+
23+
public BlockNavigation BlockNavigation
24+
{
25+
get => _blockNavigation;
26+
set => SetProperty(ref _blockNavigation, value);
27+
}
28+
29+
public CombinedTextDiff(Models.TextDiff diff, bool hasBlockNavigation, CombinedTextDiff previous = null)
30+
{
31+
Data = diff;
32+
BlockNavigation = hasBlockNavigation ? new BlockNavigation(this) : null;
33+
34+
if (previous != null && previous.File.Equals(File, StringComparison.Ordinal))
35+
ScrollOffset = previous.ScrollOffset;
36+
}
37+
38+
private Vector _scrollOffset = Vector.Zero;
39+
private BlockNavigation _blockNavigation = null;
40+
}
41+
1042
public class TwoSideTextDiff : ObservableObject
1143
{
12-
public string File { get; set; }
13-
public List<Models.TextDiffLine> Old { get; set; } = new List<Models.TextDiffLine>();
14-
public List<Models.TextDiffLine> New { get; set; } = new List<Models.TextDiffLine>();
15-
public int MaxLineNumber = 0;
44+
public Models.TextDiff Data { get; }
45+
public List<Models.TextDiffLine> Old { get; } = new List<Models.TextDiffLine>();
46+
public List<Models.TextDiffLine> New { get; } = new List<Models.TextDiffLine>();
47+
48+
public string File => Data.File;
49+
public int MaxLineNumber => Data.MaxLineNumber;
50+
public bool IsUnstaged => Data.Option.IsUnstaged;
51+
public bool EnableChunkOption => Data.Option.WorkingCopyChange != null;
1652

1753
public Vector SyncScrollOffset
1854
{
1955
get => _syncScrollOffset;
2056
set => SetProperty(ref _syncScrollOffset, value);
2157
}
2258

23-
public TwoSideTextDiff(Models.TextDiff diff, TwoSideTextDiff previous = null)
59+
public BlockNavigation BlockNavigation
2460
{
25-
File = diff.File;
26-
MaxLineNumber = diff.MaxLineNumber;
61+
get => _blockNavigation;
62+
set => SetProperty(ref _blockNavigation, value);
63+
}
64+
65+
public TwoSideTextDiff(Models.TextDiff diff, bool hasBlockNavigation, TwoSideTextDiff previous = null)
66+
{
67+
Data = diff;
2768

2869
foreach (var line in diff.Lines)
2970
{
@@ -45,8 +86,12 @@ public TwoSideTextDiff(Models.TextDiff diff, TwoSideTextDiff previous = null)
4586

4687
FillEmptyLines();
4788

48-
if (previous != null && previous.File == File)
89+
BlockNavigation = hasBlockNavigation ? new BlockNavigation(this) : null;
90+
if (previous != null && previous.File.Equals(File, StringComparison.Ordinal))
91+
{
4992
_syncScrollOffset = previous._syncScrollOffset;
93+
_blockNavigation = previous._blockNavigation;
94+
}
5095
}
5196

5297
public void ConvertsToCombinedRange(Models.TextDiff combined, ref int startLine, ref int endLine, bool isOldSide)
@@ -105,5 +150,6 @@ private void FillEmptyLines()
105150
}
106151

107152
private Vector _syncScrollOffset = Vector.Zero;
153+
private BlockNavigation _blockNavigation = null;
108154
}
109155
}

0 commit comments

Comments
 (0)