Skip to content

Commit 894f3e9

Browse files
committed
feature: supports searching revision files (#775)
1 parent 536f225 commit 894f3e9

File tree

10 files changed

+350
-15
lines changed

10 files changed

+350
-15
lines changed

src/Commands/QueryCurrentRevisionFiles.cs renamed to src/Commands/QueryRevisionFileNames.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
namespace SourceGit.Commands
22
{
3-
public class QueryCurrentRevisionFiles : Command
3+
public class QueryRevisionFileNames : Command
44
{
5-
public QueryCurrentRevisionFiles(string repo)
5+
public QueryRevisionFileNames(string repo, string revision)
66
{
77
WorkingDirectory = repo;
88
Context = repo;
9-
Args = "ls-tree -r --name-only HEAD";
9+
Args = $"ls-tree -r -z --name-only {revision}";
1010
}
1111

1212
public string[] Result()
1313
{
1414
var rs = ReadToEnd();
1515
if (rs.IsSuccess)
16-
return rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
16+
return rs.StdOut.Split('\0', System.StringSplitOptions.RemoveEmptyEntries);
1717

1818
return [];
1919
}

src/Commands/QueryRevisionObjects.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,35 @@ public QueryRevisionObjects(string repo, string sha, string parentFolder)
1212
{
1313
WorkingDirectory = repo;
1414
Context = repo;
15-
Args = $"ls-tree {sha}";
15+
Args = $"ls-tree -z {sha}";
1616

1717
if (!string.IsNullOrEmpty(parentFolder))
1818
Args += $" -- \"{parentFolder}\"";
1919
}
2020

2121
public List<Models.Object> Result()
2222
{
23-
Exec();
23+
var rs = ReadToEnd();
24+
if (rs.IsSuccess)
25+
{
26+
var start = 0;
27+
var end = rs.StdOut.IndexOf('\0', start);
28+
while (end > 0)
29+
{
30+
var line = rs.StdOut.Substring(start, end - start);
31+
Parse(line);
32+
start = end + 1;
33+
end = rs.StdOut.IndexOf('\0', start);
34+
}
35+
36+
if (start < rs.StdOut.Length)
37+
Parse(rs.StdOut.Substring(start));
38+
}
39+
2440
return _objects;
2541
}
2642

27-
protected override void OnReadline(string line)
43+
private void Parse(string line)
2844
{
2945
var match = REG_FORMAT().Match(line);
3046
if (!match.Success)

src/Resources/Locales/en_US.axaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">Search Changes...</x:String>
122122
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">FILES</x:String>
123123
<x:String x:Key="Text.CommitDetail.Files.LFS" xml:space="preserve">LFS File</x:String>
124+
<x:String x:Key="Text.CommitDetail.Files.Search" xml:space="preserve">Search Files...</x:String>
124125
<x:String x:Key="Text.CommitDetail.Files.Submodule" xml:space="preserve">Submodule</x:String>
125126
<x:String x:Key="Text.CommitDetail.Info" xml:space="preserve">INFORMATION</x:String>
126127
<x:String x:Key="Text.CommitDetail.Info.Author" xml:space="preserve">AUTHOR</x:String>

src/Resources/Locales/zh_CN.axaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">查找变更...</x:String>
125125
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">文件列表</x:String>
126126
<x:String x:Key="Text.CommitDetail.Files.LFS" xml:space="preserve">LFS文件</x:String>
127+
<x:String x:Key="Text.CommitDetail.Files.Search" xml:space="preserve">查找文件...</x:String>
127128
<x:String x:Key="Text.CommitDetail.Files.Submodule" xml:space="preserve">子模块</x:String>
128129
<x:String x:Key="Text.CommitDetail.Info" xml:space="preserve">基本信息</x:String>
129130
<x:String x:Key="Text.CommitDetail.Info.Author" xml:space="preserve">修改者</x:String>

src/Resources/Locales/zh_TW.axaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">搜尋變更...</x:String>
125125
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">檔案列表</x:String>
126126
<x:String x:Key="Text.CommitDetail.Files.LFS" xml:space="preserve">LFS 檔案</x:String>
127+
<x:String x:Key="Text.CommitDetail.Files.Search" xml:space="preserve">搜尋檔案...</x:String>
127128
<x:String x:Key="Text.CommitDetail.Files.Submodule" xml:space="preserve">子模組</x:String>
128129
<x:String x:Key="Text.CommitDetail.Info" xml:space="preserve">基本資訊</x:String>
129130
<x:String x:Key="Text.CommitDetail.Info.Author" xml:space="preserve">作者</x:String>

src/ViewModels/CommitDetail.cs

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public AvaloniaList<string> Children
8282
{
8383
get;
8484
private set;
85-
} = new AvaloniaList<string>();
85+
} = [];
8686

8787
public string SearchChangeFilter
8888
{
@@ -106,13 +106,68 @@ public AvaloniaList<Models.CommitLink> WebLinks
106106
{
107107
get;
108108
private set;
109-
} = new AvaloniaList<Models.CommitLink>();
109+
} = [];
110110

111111
public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
112112
{
113113
get => _repo.Settings?.IssueTrackerRules;
114114
}
115115

116+
public string RevisionFileSearchFilter
117+
{
118+
get => _revisionFileSearchFilter;
119+
set
120+
{
121+
if (SetProperty(ref _revisionFileSearchFilter, value))
122+
{
123+
RevisionFileSearchSuggestion.Clear();
124+
125+
if (!string.IsNullOrEmpty(value))
126+
{
127+
if (_revisionFiles.Count == 0)
128+
{
129+
var sha = Commit.SHA;
130+
131+
Task.Run(() =>
132+
{
133+
var files = new Commands.QueryRevisionFileNames(_repo.FullPath, sha).Result();
134+
135+
Dispatcher.UIThread.Invoke(() => {
136+
if (sha == Commit.SHA)
137+
{
138+
_revisionFiles.Clear();
139+
_revisionFiles.AddRange(files);
140+
UpdateRevisionFileSearchSuggestion();
141+
}
142+
});
143+
});
144+
}
145+
else
146+
{
147+
UpdateRevisionFileSearchSuggestion();
148+
}
149+
}
150+
else
151+
{
152+
IsRevisionFileSearchSuggestionOpen = false;
153+
GC.Collect();
154+
}
155+
}
156+
}
157+
}
158+
159+
public AvaloniaList<string> RevisionFileSearchSuggestion
160+
{
161+
get;
162+
private set;
163+
} = [];
164+
165+
public bool IsRevisionFileSearchSuggestionOpen
166+
{
167+
get => _isRevisionFileSearchSuggestionOpen;
168+
set => SetProperty(ref _isRevisionFileSearchSuggestionOpen, value);
169+
}
170+
116171
public CommitDetail(Repository repo)
117172
{
118173
_repo = repo;
@@ -147,17 +202,23 @@ public void Cleanup()
147202
{
148203
_repo = null;
149204
_commit = null;
205+
150206
if (_changes != null)
151207
_changes.Clear();
152208
if (_visibleChanges != null)
153209
_visibleChanges.Clear();
154210
if (_selectedChanges != null)
155211
_selectedChanges.Clear();
212+
156213
_signInfo = null;
157214
_searchChangeFilter = null;
158215
_diffContext = null;
159216
_viewRevisionFileContent = null;
160217
_cancelToken = null;
218+
219+
WebLinks.Clear();
220+
_revisionFiles.Clear();
221+
RevisionFileSearchSuggestion.Clear();
161222
}
162223

163224
public void NavigateTo(string commitSHA)
@@ -175,6 +236,11 @@ public void ClearSearchChangeFilter()
175236
SearchChangeFilter = string.Empty;
176237
}
177238

239+
public void ClearRevisionFileSearchFilter()
240+
{
241+
RevisionFileSearchFilter = string.Empty;
242+
}
243+
178244
public Models.Commit GetParent(string sha)
179245
{
180246
return new Commands.QuerySingleCommit(_repo.FullPath, sha).Result();
@@ -543,13 +609,17 @@ public ContextMenu CreateRevisionFileContextMenu(Models.Object file)
543609
private void Refresh()
544610
{
545611
_changes = null;
612+
_revisionFiles.Clear();
613+
546614
FullMessage = string.Empty;
547615
SignInfo = null;
548616
Changes = [];
549617
VisibleChanges = null;
550618
SelectedChanges = null;
551619
ViewRevisionFileContent = null;
552620
Children.Clear();
621+
RevisionFileSearchFilter = string.Empty;
622+
IsRevisionFileSearchSuggestionOpen = false;
553623

554624
if (_commit == null)
555625
return;
@@ -716,6 +786,24 @@ private void TryToAddContextMenuItemsForGitLFS(ContextMenu menu, string path)
716786
menu.Items.Add(new MenuItem() { Header = "-" });
717787
}
718788

789+
private void UpdateRevisionFileSearchSuggestion()
790+
{
791+
var suggestion = new List<string>();
792+
foreach (var file in _revisionFiles)
793+
{
794+
if (file.Contains(_revisionFileSearchFilter, StringComparison.OrdinalIgnoreCase) &&
795+
file.Length != _revisionFileSearchFilter.Length)
796+
suggestion.Add(file);
797+
798+
if (suggestion.Count >= 100)
799+
break;
800+
}
801+
802+
RevisionFileSearchSuggestion.Clear();
803+
RevisionFileSearchSuggestion.AddRange(suggestion);
804+
IsRevisionFileSearchSuggestionOpen = suggestion.Count > 0;
805+
}
806+
719807
[GeneratedRegex(@"^version https://git-lfs.github.com/spec/v\d+\r?\noid sha256:([0-9a-f]+)\r?\nsize (\d+)[\r\n]*$")]
720808
private static partial Regex REG_LFS_FORMAT();
721809

@@ -736,5 +824,8 @@ private void TryToAddContextMenuItemsForGitLFS(ContextMenu menu, string path)
736824
private DiffContext _diffContext = null;
737825
private object _viewRevisionFileContent = null;
738826
private Commands.Command.CancelToken _cancelToken = null;
827+
private List<string> _revisionFiles = [];
828+
private string _revisionFileSearchFilter = string.Empty;
829+
private bool _isRevisionFileSearchSuggestionOpen = false;
739830
}
740831
}

src/ViewModels/Repository.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2147,7 +2147,7 @@ private void UpdateCurrentRevisionFilesForSearchSuggestion()
21472147
{
21482148
Task.Run(() =>
21492149
{
2150-
var files = new Commands.QueryCurrentRevisionFiles(_fullpath).Result();
2150+
var files = new Commands.QueryRevisionFileNames(_fullpath, "HEAD").Result();
21512151
Dispatcher.UIThread.Invoke(() =>
21522152
{
21532153
if (_searchCommitFilterType != 3)

src/Views/RevisionFileTreeView.axaml.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,68 @@ public RevisionFileTreeView()
144144
InitializeComponent();
145145
}
146146

147+
public void SetSearchResult(string file)
148+
{
149+
_rows.Clear();
150+
_searchResult.Clear();
151+
152+
var rows = new List<ViewModels.RevisionFileTreeNode>();
153+
if (string.IsNullOrEmpty(file))
154+
{
155+
MakeRows(rows, _tree, 0);
156+
}
157+
else
158+
{
159+
var vm = DataContext as ViewModels.CommitDetail;
160+
if (vm == null || vm.Commit == null)
161+
return;
162+
163+
var objects = vm.GetRevisionFilesUnderFolder(file);
164+
if (objects == null || objects.Count != 1)
165+
return;
166+
167+
var routes = file.Split('/', StringSplitOptions.None);
168+
if (routes.Length == 1)
169+
{
170+
_searchResult.Add(new ViewModels.RevisionFileTreeNode
171+
{
172+
Backend = objects[0]
173+
});
174+
}
175+
else
176+
{
177+
var last = _searchResult;
178+
var prefix = string.Empty;
179+
for (var i = 0; i < routes.Length - 1; i++)
180+
{
181+
var folder = new ViewModels.RevisionFileTreeNode
182+
{
183+
Backend = new Models.Object
184+
{
185+
Type = Models.ObjectType.Tree,
186+
Path = prefix + routes[i],
187+
},
188+
IsExpanded = true,
189+
};
190+
191+
last.Add(folder);
192+
last = folder.Children;
193+
prefix = folder.Backend + "/";
194+
}
195+
196+
last.Add(new ViewModels.RevisionFileTreeNode
197+
{
198+
Backend = objects[0]
199+
});
200+
}
201+
202+
MakeRows(rows, _searchResult, 0);
203+
}
204+
205+
_rows.AddRange(rows);
206+
GC.Collect();
207+
}
208+
147209
public void ToggleNodeIsExpanded(ViewModels.RevisionFileTreeNode node)
148210
{
149211
_disableSelectionChangingEvent = true;
@@ -189,6 +251,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
189251
{
190252
_tree.Clear();
191253
_rows.Clear();
254+
_searchResult.Clear();
192255

193256
var vm = DataContext as ViewModels.CommitDetail;
194257
if (vm == null || vm.Commit == null)
@@ -308,5 +371,6 @@ private void MakeRows(List<ViewModels.RevisionFileTreeNode> rows, List<ViewModel
308371
private List<ViewModels.RevisionFileTreeNode> _tree = [];
309372
private AvaloniaList<ViewModels.RevisionFileTreeNode> _rows = [];
310373
private bool _disableSelectionChangingEvent = false;
374+
private List<ViewModels.RevisionFileTreeNode> _searchResult = [];
311375
}
312376
}

0 commit comments

Comments
 (0)