Skip to content

Commit 96e2754

Browse files
committed
fix: support to switch blaming revision with renamed files (#2040)
Signed-off-by: leo <[email protected]>
1 parent 46c1e4b commit 96e2754

File tree

5 files changed

+90
-56
lines changed

5 files changed

+90
-56
lines changed

src/Commands/Blame.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,15 @@ namespace SourceGit.Commands
77
{
88
public partial class Blame : Command
99
{
10-
[GeneratedRegex(@"^\^?([0-9a-f]+)\s+.*\((.*)\s+(\d+)\s+[\-\+]?\d+\s+\d+\) (.*)")]
10+
[GeneratedRegex(@"^\^?([0-9a-f]+)\s+(.*)\s+\((.*)\s+(\d+)\s+[\-\+]?\d+\s+\d+\) (.*)")]
1111
private static partial Regex REG_FORMAT();
1212

1313
public Blame(string repo, string file, string revision)
1414
{
1515
WorkingDirectory = repo;
1616
Context = repo;
17-
Args = $"blame -t {revision} -- {file.Quoted()}";
17+
Args = $"blame -f -t {revision} -- {file.Quoted()}";
1818
RaiseError = false;
19-
20-
_result.File = file;
2119
}
2220

2321
public async Task<Models.BlameData> ReadAsync()
@@ -61,19 +59,20 @@ private void ParseLine(string line)
6159
if (!match.Success)
6260
return;
6361

64-
_content.AppendLine(match.Groups[4].Value);
62+
_content.AppendLine(match.Groups[5].Value);
6563

6664
var commit = match.Groups[1].Value;
67-
var author = match.Groups[2].Value;
68-
var timestamp = int.Parse(match.Groups[3].Value);
69-
var when = DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime().ToString(_dateFormat);
65+
var file = match.Groups[2].Value.Trim();
66+
var author = match.Groups[3].Value;
67+
var timestamp = ulong.Parse(match.Groups[4].Value);
7068

7169
var info = new Models.BlameLineInfo()
7270
{
7371
IsFirstInGroup = commit != _lastSHA,
7472
CommitSHA = commit,
73+
File = file,
7574
Author = author,
76-
Time = when,
75+
Timestamp = timestamp,
7776
};
7877

7978
_result.LineInfos.Add(info);
@@ -88,7 +87,6 @@ private void ParseLine(string line)
8887

8988
private readonly Models.BlameData _result = new Models.BlameData();
9089
private readonly StringBuilder _content = new StringBuilder();
91-
private readonly string _dateFormat = Models.DateTimeFormat.Active.DateOnly;
9290
private string _lastSHA = string.Empty;
9391
private bool _needUnifyCommitSHA = false;
9492
private int _minSHALen = 64;

src/Models/Blame.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23

34
namespace SourceGit.Models
45
{
56
public class BlameLineInfo
67
{
78
public bool IsFirstInGroup { get; set; } = false;
89
public string CommitSHA { get; set; } = string.Empty;
10+
public string File { get; set; } = string.Empty;
911
public string Author { get; set; } = string.Empty;
10-
public string Time { get; set; } = string.Empty;
12+
public ulong Timestamp { get; set; } = 0;
13+
public string Time => DateTime.UnixEpoch.AddSeconds(Timestamp).ToLocalTime().ToString(DateTimeFormat.Active.DateOnly);
1114
}
1215

1316
public class BlameData
1417
{
15-
public string File { get; set; } = string.Empty;
16-
public List<BlameLineInfo> LineInfos { get; set; } = new List<BlameLineInfo>();
17-
public string Content { get; set; } = string.Empty;
1818
public bool IsBinary { get; set; } = false;
19+
public string Content { get; set; } = string.Empty;
20+
public List<BlameLineInfo> LineInfos { get; set; } = [];
1921
}
2022
}

src/ViewModels/Blame.cs

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ namespace SourceGit.ViewModels
1010
{
1111
public class Blame : ObservableObject
1212
{
13-
public string FilePath
13+
public string File
1414
{
15-
get;
15+
get => _file;
16+
private set => SetProperty(ref _file, value);
1617
}
1718

1819
public Models.Commit Revision
@@ -55,14 +56,9 @@ public bool CanForward
5556
public Blame(string repo, string file, Models.Commit commit)
5657
{
5758
var sha = commit.SHA.Substring(0, 10);
58-
59-
FilePath = file;
60-
Revision = commit;
61-
PrevRevision = null;
62-
6359
_repo = repo;
64-
_navigationHistory.Add(sha);
65-
SetBlameData(sha);
60+
_navigationHistory.Add(new RevisionInfo(file, sha));
61+
SetBlameData(_navigationHistory[0]);
6662
}
6763

6864
public string GetCommitMessage(string sha)
@@ -83,7 +79,7 @@ public void Back()
8379
_navigationActiveIndex--;
8480
OnPropertyChanged(nameof(CanBack));
8581
OnPropertyChanged(nameof(CanForward));
86-
NavigateToCommit(_navigationHistory[_navigationActiveIndex], true);
82+
NavigateToCommit(_navigationHistory[_navigationActiveIndex]);
8783
}
8884

8985
public void Forward()
@@ -94,65 +90,80 @@ public void Forward()
9490
_navigationActiveIndex++;
9591
OnPropertyChanged(nameof(CanBack));
9692
OnPropertyChanged(nameof(CanForward));
97-
NavigateToCommit(_navigationHistory[_navigationActiveIndex], true);
93+
NavigateToCommit(_navigationHistory[_navigationActiveIndex]);
9894
}
9995

10096
public void GotoPrevRevision()
10197
{
102-
if (_prevRevision == null)
103-
return;
104-
105-
NavigateToCommit(_prevRevision.SHA, false);
98+
if (_prevRevision != null)
99+
NavigateToCommit(_file, _prevRevision.SHA.Substring(0, 10));
106100
}
107101

108-
public void NavigateToCommit(string commitSHA, bool isBackOrForward)
102+
public void NavigateToCommit(string file, string sha)
109103
{
110104
if (App.GetLauncher() is { Pages: { } pages })
111105
{
112106
foreach (var page in pages)
113107
{
114108
if (page.Data is Repository repo && repo.FullPath.Equals(_repo))
115109
{
116-
repo.NavigateToCommit(commitSHA);
110+
repo.NavigateToCommit(sha);
117111
break;
118112
}
119113
}
120114
}
121115

122-
if (Revision.SHA.StartsWith(commitSHA, StringComparison.Ordinal))
116+
if (Revision.SHA.StartsWith(sha, StringComparison.Ordinal))
123117
return;
124118

125-
if (!isBackOrForward)
119+
var count = _navigationHistory.Count;
120+
if (_navigationActiveIndex < count - 1)
121+
_navigationHistory.RemoveRange(_navigationActiveIndex + 1, count - _navigationActiveIndex - 1);
122+
123+
var rev = new RevisionInfo(file, sha);
124+
_navigationHistory.Add(rev);
125+
_navigationActiveIndex++;
126+
OnPropertyChanged(nameof(CanBack));
127+
OnPropertyChanged(nameof(CanForward));
128+
SetBlameData(rev);
129+
}
130+
131+
private void NavigateToCommit(RevisionInfo rev)
132+
{
133+
if (App.GetLauncher() is { Pages: { } pages })
126134
{
127-
var count = _navigationHistory.Count;
128-
if (_navigationActiveIndex < count - 1)
129-
_navigationHistory.RemoveRange(_navigationActiveIndex + 1, count - _navigationActiveIndex - 1);
130-
131-
_navigationHistory.Add(commitSHA);
132-
_navigationActiveIndex++;
133-
OnPropertyChanged(nameof(CanBack));
134-
OnPropertyChanged(nameof(CanForward));
135+
foreach (var page in pages)
136+
{
137+
if (page.Data is Repository repo && repo.FullPath.Equals(_repo))
138+
{
139+
repo.NavigateToCommit(rev.SHA);
140+
break;
141+
}
142+
}
135143
}
136144

137-
SetBlameData(commitSHA);
145+
if (!Revision.SHA.StartsWith(rev.SHA, StringComparison.Ordinal))
146+
SetBlameData(rev);
138147
}
139148

140-
private void SetBlameData(string commitSHA)
149+
private void SetBlameData(RevisionInfo rev)
141150
{
142151
if (_cancellationSource is { IsCancellationRequested: false })
143152
_cancellationSource.Cancel();
144153

145154
_cancellationSource = new CancellationTokenSource();
146155
var token = _cancellationSource.Token;
147156

157+
File = rev.File;
158+
148159
Task.Run(async () =>
149160
{
150161
var argsBuilder = new StringBuilder();
151162
argsBuilder
152163
.Append("--date-order -n 2 ")
153-
.Append(commitSHA ?? string.Empty)
164+
.Append(rev.SHA)
154165
.Append(" -- ")
155-
.Append(FilePath.Quoted());
166+
.Append(rev.File.Quoted());
156167

157168
var commits = await new Commands.QueryCommits(_repo, argsBuilder.ToString(), false)
158169
.GetResultAsync()
@@ -163,14 +174,14 @@ private void SetBlameData(string commitSHA)
163174
if (!token.IsCancellationRequested)
164175
{
165176
Revision = commits.Count > 0 ? commits[0] : null;
166-
PrevRevision = commits.Count == 2 ? commits[1] : null;
177+
PrevRevision = commits.Count > 1 ? commits[1] : null;
167178
}
168179
});
169180
});
170181

171182
Task.Run(async () =>
172183
{
173-
var result = await new Commands.Blame(_repo, FilePath, commitSHA)
184+
var result = await new Commands.Blame(_repo, rev.File, rev.SHA)
174185
.ReadAsync()
175186
.ConfigureAwait(false);
176187

@@ -182,12 +193,25 @@ private void SetBlameData(string commitSHA)
182193
}, token);
183194
}
184195

196+
private class RevisionInfo
197+
{
198+
public string File { get; set; } = string.Empty;
199+
public string SHA { get; set; } = string.Empty;
200+
201+
public RevisionInfo(string file, string sha)
202+
{
203+
File = file;
204+
SHA = sha;
205+
}
206+
}
207+
185208
private string _repo;
209+
private string _file;
186210
private Models.Commit _revision;
187211
private Models.Commit _prevRevision;
188212
private CancellationTokenSource _cancellationSource = null;
189213
private int _navigationActiveIndex = 0;
190-
private List<string> _navigationHistory = [];
214+
private List<RevisionInfo> _navigationHistory = [];
191215
private Models.BlameData _data = null;
192216
private Dictionary<string, string> _commitMessages = new();
193217
}

src/Views/Blame.axaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
<TextBlock Grid.Column="1"
4747
Margin="4,0,0,0"
4848
VerticalAlignment="Center"
49-
Text="{Binding FilePath, Mode=OneWay}"/>
49+
Text="{Binding File, Mode=OneWay}"/>
5050

5151
<Button Grid.Column="2"
5252
Classes="icon_button"
@@ -101,6 +101,7 @@
101101
FontFamily="{DynamicResource Fonts.Monospace}"
102102
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=EditorFontSize}"
103103
TabWidth="{Binding Source={x:Static vm:Preferences.Instance}, Path=EditorTabWidth}"
104+
File="{Binding File, Mode=OneWay}"
104105
BlameData="{Binding Data}"
105106
IsVisible="{Binding IsBinary, Converter={x:Static BoolConverters.Not}}">
106107
<ToolTip.IsOpen>

src/Views/Blame.axaml.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ protected override void OnPointerPressed(PointerPressedEventArgs e)
223223
if (rect.Contains(pos))
224224
{
225225
if (DataContext is ViewModels.Blame blame)
226-
blame.NavigateToCommit(info.CommitSHA, false);
226+
blame.NavigateToCommit(info.File, info.CommitSHA);
227227

228228
e.Handled = true;
229229
break;
@@ -256,6 +256,15 @@ protected override Size MeasureOverride(Size availableSize)
256256
private readonly BlameTextEditor _editor = null;
257257
}
258258

259+
public static readonly StyledProperty<string> FileProperty =
260+
AvaloniaProperty.Register<BlameTextEditor, string>(nameof(File));
261+
262+
public string File
263+
{
264+
get => GetValue(FileProperty);
265+
set => SetValue(FileProperty, value);
266+
}
267+
259268
public static readonly StyledProperty<Models.BlameData> BlameDataProperty =
260269
AvaloniaProperty.Register<BlameTextEditor, Models.BlameData>(nameof(BlameData));
261270

@@ -350,17 +359,17 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
350359
{
351360
base.OnPropertyChanged(change);
352361

362+
if (change.Property == FileProperty)
363+
{
364+
if (File is { Length: > 0 })
365+
Models.TextMateHelper.SetGrammarByFileName(_textMate, File);
366+
}
353367
if (change.Property == BlameDataProperty)
354368
{
355369
if (BlameData is { IsBinary: false } blame)
356-
{
357-
Models.TextMateHelper.SetGrammarByFileName(_textMate, blame.File);
358370
Text = blame.Content;
359-
}
360371
else
361-
{
362372
Text = string.Empty;
363-
}
364373
}
365374
else if (change.Property == TabWidthProperty)
366375
{

0 commit comments

Comments
 (0)