Skip to content

Commit b75676a

Browse files
committed
refactor: commit message
- move issue tracker and commit hash links parsing to view models - parsing links async - make sure matched hash is a valid commit oid - disable `CHILDREN` row in submodule info panel Signed-off-by: leo <[email protected]>
1 parent 5301a36 commit b75676a

17 files changed

+191
-186
lines changed

src/Commands/IsCommitSHA.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace SourceGit.Commands
2+
{
3+
public class IsCommitSHA : Command
4+
{
5+
public IsCommitSHA(string repo, string hash)
6+
{
7+
WorkingDirectory = repo;
8+
Args = $"cat-file -t {hash}";
9+
}
10+
11+
public bool Result()
12+
{
13+
var rs = ReadToEnd();
14+
return rs.IsSuccess && rs.StdOut.Trim().Equals("commit");
15+
}
16+
}
17+
}

src/Commands/QueryCommitsWithFullMessage.cs renamed to src/Commands/QueryCommitsForInteractiveRebase.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33

44
namespace SourceGit.Commands
55
{
6-
public class QueryCommitsWithFullMessage : Command
6+
public class QueryCommitsForInteractiveRebase : Command
77
{
8-
public QueryCommitsWithFullMessage(string repo, string args)
8+
public QueryCommitsForInteractiveRebase(string repo, string on)
99
{
1010
_boundary = $"----- BOUNDARY OF COMMIT {Guid.NewGuid()} -----";
1111

1212
WorkingDirectory = repo;
1313
Context = repo;
14-
Args = $"log --date-order --no-show-signature --decorate=full --pretty=format:\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_boundary}\" {args}";
14+
Args = $"log --date-order --no-show-signature --decorate=full --pretty=format:\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_boundary}\" {on}..HEAD";
1515
}
1616

17-
public List<Models.CommitWithMessage> Result()
17+
public List<Models.InteractiveCommit> Result()
1818
{
1919
var rs = ReadToEnd();
2020
if (!rs.IsSuccess)
@@ -29,7 +29,7 @@ public QueryCommitsWithFullMessage(string repo, string args)
2929
switch (nextPartIdx)
3030
{
3131
case 0:
32-
_current = new Models.CommitWithMessage();
32+
_current = new Models.InteractiveCommit();
3333
_current.Commit.SHA = line;
3434
_commits.Add(_current);
3535
break;
@@ -52,7 +52,7 @@ public QueryCommitsWithFullMessage(string repo, string args)
5252
_current.Commit.CommitterTime = ulong.Parse(line);
5353
break;
5454
default:
55-
var boundary = rs.StdOut.IndexOf(_boundary, end + 1);
55+
var boundary = rs.StdOut.IndexOf(_boundary, end + 1, StringComparison.Ordinal);
5656
if (boundary > end)
5757
{
5858
_current.Message = rs.StdOut.Substring(start, boundary - start - 1);
@@ -88,8 +88,8 @@ private void ParseParent(string data)
8888
_current.Commit.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries));
8989
}
9090

91-
private List<Models.CommitWithMessage> _commits = new List<Models.CommitWithMessage>();
92-
private Models.CommitWithMessage _current = null;
91+
private List<Models.InteractiveCommit> _commits = [];
92+
private Models.InteractiveCommit _current = null;
9393
private string _boundary = "";
9494
}
9595
}

src/Models/Commit.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ public void ParseDecorators(string data)
112112
}
113113
}
114114

115-
public class CommitWithMessage
115+
public class CommitFullMessage
116116
{
117-
public Commit Commit { get; set; } = new Commit();
118-
public string Message { get; set; } = "";
117+
public string Message { get; set; } = string.Empty;
118+
public List<Hyperlink> Links { get; set; } = [];
119119
}
120120
}

src/Models/InteractiveRebase.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ public enum InteractiveRebaseAction
1212
Drop,
1313
}
1414

15+
public class InteractiveCommit
16+
{
17+
public Commit Commit { get; set; } = new Commit();
18+
public string Message { get; set; } = string.Empty;
19+
}
20+
1521
public class InteractiveRebaseJob
1622
{
1723
public string SHA { get; set; } = string.Empty;

src/Models/RevisionFile.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ public class RevisionLFSObject
2929
public class RevisionSubmodule
3030
{
3131
public Commit Commit { get; set; } = null;
32-
public string FullMessage { get; set; } = string.Empty;
32+
public CommitFullMessage FullMessage { get; set; } = null;
3333
}
3434
}

src/ViewModels/CommitDetail.cs

Lines changed: 88 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Text.RegularExpressions;
66
using System.Threading.Tasks;
77

8-
using Avalonia.Collections;
98
using Avalonia.Controls;
109
using Avalonia.Media.Imaging;
1110
using Avalonia.Platform.Storage;
@@ -46,7 +45,7 @@ public Models.Commit Commit
4645
}
4746
}
4847

49-
public string FullMessage
48+
public Models.CommitFullMessage FullMessage
5049
{
5150
get => _fullMessage;
5251
private set => SetProperty(ref _fullMessage, value);
@@ -85,11 +84,11 @@ public List<Models.Change> SelectedChanges
8584
}
8685
}
8786

88-
public AvaloniaList<string> Children
87+
public List<string> Children
8988
{
90-
get;
91-
private set;
92-
} = [];
89+
get => _children;
90+
private set => SetProperty(ref _children, value);
91+
}
9392

9493
public string SearchChangeFilter
9594
{
@@ -109,43 +108,36 @@ public object ViewRevisionFileContent
109108
set => SetProperty(ref _viewRevisionFileContent, value);
110109
}
111110

112-
public AvaloniaList<Models.CommitLink> WebLinks
111+
public List<Models.CommitLink> WebLinks
113112
{
114113
get;
115114
private set;
116115
} = [];
117116

118-
public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
119-
{
120-
get => _repo.Settings?.IssueTrackerRules;
121-
}
122-
123117
public string RevisionFileSearchFilter
124118
{
125119
get => _revisionFileSearchFilter;
126120
set
127121
{
128122
if (SetProperty(ref _revisionFileSearchFilter, value))
129123
{
130-
RevisionFileSearchSuggestion.Clear();
131-
132124
if (!string.IsNullOrEmpty(value))
133125
{
134-
if (_revisionFiles.Count == 0)
126+
if (_revisionFiles == null)
135127
{
136128
var sha = Commit.SHA;
137129

138130
Task.Run(() =>
139131
{
140132
var files = new Commands.QueryRevisionFileNames(_repo.FullPath, sha).Result();
133+
var filesList = new List<string>();
134+
filesList.AddRange(files);
141135

142136
Dispatcher.UIThread.Invoke(() =>
143137
{
144138
if (sha == Commit.SHA)
145139
{
146-
_revisionFiles.Clear();
147-
_revisionFiles.AddRange(files);
148-
140+
_revisionFiles = filesList;
149141
if (!string.IsNullOrEmpty(_revisionFileSearchFilter))
150142
UpdateRevisionFileSearchSuggestion();
151143
}
@@ -159,23 +151,17 @@ public string RevisionFileSearchFilter
159151
}
160152
else
161153
{
162-
IsRevisionFileSearchSuggestionOpen = false;
154+
RevisionFileSearchSuggestion = null;
163155
GC.Collect();
164156
}
165157
}
166158
}
167159
}
168160

169-
public AvaloniaList<string> RevisionFileSearchSuggestion
161+
public List<string> RevisionFileSearchSuggestion
170162
{
171-
get;
172-
private set;
173-
} = [];
174-
175-
public bool IsRevisionFileSearchSuggestionOpen
176-
{
177-
get => _isRevisionFileSearchSuggestionOpen;
178-
set => SetProperty(ref _isRevisionFileSearchSuggestionOpen, value);
163+
get => _revisionFileSearchSuggestion;
164+
private set => SetProperty(ref _revisionFileSearchSuggestion, value);
179165
}
180166

181167
public CommitDetail(Repository repo)
@@ -212,23 +198,17 @@ public void Cleanup()
212198
{
213199
_repo = null;
214200
_commit = null;
215-
216-
if (_changes != null)
217-
_changes.Clear();
218-
if (_visibleChanges != null)
219-
_visibleChanges.Clear();
220-
if (_selectedChanges != null)
221-
_selectedChanges.Clear();
222-
201+
_changes = null;
202+
_visibleChanges = null;
203+
_selectedChanges = null;
223204
_signInfo = null;
224205
_searchChangeFilter = null;
225206
_diffContext = null;
226207
_viewRevisionFileContent = null;
227208
_cancelToken = null;
228-
229209
WebLinks.Clear();
230-
_revisionFiles.Clear();
231-
RevisionFileSearchSuggestion.Clear();
210+
_revisionFiles = null;
211+
_revisionFileSearchSuggestion = null;
232212
}
233213

234214
public void NavigateTo(string commitSHA)
@@ -251,6 +231,11 @@ public void ClearRevisionFileSearchFilter()
251231
RevisionFileSearchFilter = string.Empty;
252232
}
253233

234+
public void CancelRevisionFileSuggestions()
235+
{
236+
RevisionFileSearchSuggestion = null;
237+
}
238+
254239
public Models.Commit GetParent(string sha)
255240
{
256241
return new Commands.QuerySingleCommit(_repo.FullPath, sha).Result();
@@ -322,7 +307,12 @@ public void ViewRevisionFile(Models.Object file)
322307
if (commit != null)
323308
{
324309
var body = new Commands.QueryCommitFullMessage(submoduleRoot, file.SHA).Result();
325-
var submodule = new Models.RevisionSubmodule() { Commit = commit, FullMessage = body };
310+
var submodule = new Models.RevisionSubmodule()
311+
{
312+
Commit = commit,
313+
FullMessage = new Models.CommitFullMessage { Message = body }
314+
};
315+
326316
Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = submodule);
327317
}
328318
else
@@ -332,7 +322,7 @@ public void ViewRevisionFile(Models.Object file)
332322
ViewRevisionFileContent = new Models.RevisionSubmodule()
333323
{
334324
Commit = new Models.Commit() { SHA = file.SHA },
335-
FullMessage = string.Empty,
325+
FullMessage = null,
336326
};
337327
});
338328
}
@@ -622,23 +612,22 @@ public ContextMenu CreateRevisionFileContextMenu(Models.Object file)
622612
private void Refresh()
623613
{
624614
_changes = null;
625-
_revisionFiles.Clear();
615+
_revisionFiles = null;
626616

627617
SignInfo = null;
628618
ViewRevisionFileContent = null;
629-
Children.Clear();
619+
Children = null;
630620
RevisionFileSearchFilter = string.Empty;
631-
IsRevisionFileSearchSuggestionOpen = false;
632-
633-
GC.Collect();
621+
RevisionFileSearchSuggestion = null;
634622

635623
if (_commit == null)
636624
return;
637625

638626
Task.Run(() =>
639627
{
640-
var fullMessage = new Commands.QueryCommitFullMessage(_repo.FullPath, _commit.SHA).Result();
641-
Dispatcher.UIThread.Invoke(() => FullMessage = fullMessage);
628+
var message = new Commands.QueryCommitFullMessage(_repo.FullPath, _commit.SHA).Result();
629+
var links = ParseLinksInMessage(message);
630+
Dispatcher.UIThread.Invoke(() => FullMessage = new Models.CommitFullMessage { Message = message, Links = links });
642631
});
643632

644633
Task.Run(() =>
@@ -694,6 +683,49 @@ private void Refresh()
694683
});
695684
}
696685

686+
private List<Models.Hyperlink> ParseLinksInMessage(string message)
687+
{
688+
var links = new List<Models.Hyperlink>();
689+
if (_repo.Settings.IssueTrackerRules is { Count: > 0 } rules)
690+
{
691+
foreach (var rule in rules)
692+
rule.Matches(links, message);
693+
}
694+
695+
var shas = REG_SHA_FORMAT().Matches(message);
696+
for (int i = 0; i < shas.Count; i++)
697+
{
698+
var sha = shas[i];
699+
if (!sha.Success)
700+
continue;
701+
702+
var hash = sha.Groups[1].Value;
703+
var test = new Commands.IsCommitSHA(_repo.FullPath, hash).Result();
704+
if (!test)
705+
continue;
706+
707+
var start = sha.Index;
708+
var len = sha.Length;
709+
var intersect = false;
710+
foreach (var link in links)
711+
{
712+
if (link.Intersect(start, len))
713+
{
714+
intersect = true;
715+
break;
716+
}
717+
}
718+
719+
if (!intersect)
720+
links.Add(new Models.Hyperlink(start, len, hash, true));
721+
}
722+
723+
if (links.Count > 0)
724+
links.Sort((l, r) => l.Start - r.Start);
725+
726+
return links;
727+
}
728+
697729
private void RefreshVisibleChanges()
698730
{
699731
if (_changes == null)
@@ -813,11 +845,12 @@ private void UpdateRevisionFileSearchSuggestion()
813845
break;
814846
}
815847

816-
RevisionFileSearchSuggestion.Clear();
817-
RevisionFileSearchSuggestion.AddRange(suggestion);
818-
IsRevisionFileSearchSuggestionOpen = suggestion.Count > 0;
848+
RevisionFileSearchSuggestion = suggestion;
819849
}
820850

851+
[GeneratedRegex(@"\b([0-9a-fA-F]{6,40})\b")]
852+
private static partial Regex REG_SHA_FORMAT();
853+
821854
[GeneratedRegex(@"^version https://git-lfs.github.com/spec/v\d+\r?\noid sha256:([0-9a-f]+)\r?\nsize (\d+)[\r\n]*$")]
822855
private static partial Regex REG_LFS_FORMAT();
823856

@@ -828,17 +861,18 @@ private void UpdateRevisionFileSearchSuggestion()
828861

829862
private Repository _repo = null;
830863
private Models.Commit _commit = null;
831-
private string _fullMessage = string.Empty;
864+
private Models.CommitFullMessage _fullMessage = null;
832865
private Models.CommitSignInfo _signInfo = null;
866+
private List<string> _children = null;
833867
private List<Models.Change> _changes = null;
834868
private List<Models.Change> _visibleChanges = null;
835869
private List<Models.Change> _selectedChanges = null;
836870
private string _searchChangeFilter = string.Empty;
837871
private DiffContext _diffContext = null;
838872
private object _viewRevisionFileContent = null;
839873
private Commands.Command.CancelToken _cancelToken = null;
840-
private List<string> _revisionFiles = [];
874+
private List<string> _revisionFiles = null;
841875
private string _revisionFileSearchFilter = string.Empty;
842-
private bool _isRevisionFileSearchSuggestionOpen = false;
876+
private List<string> _revisionFileSearchSuggestion = null;
843877
}
844878
}

0 commit comments

Comments
 (0)