mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-05-24 13:45:00 +00:00
refactor: rewrite the histories filter function to supports both include
and exclude
modes (#690)
Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
parent
e3ffe3ef6c
commit
ca5bc4b4df
27 changed files with 767 additions and 309 deletions
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Media;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
@ -13,15 +11,16 @@ namespace SourceGit.ViewModels
|
|||
public class BranchTreeNode : ObservableObject
|
||||
{
|
||||
public string Name { get; private set; } = string.Empty;
|
||||
public string Path { get; private set; } = string.Empty;
|
||||
public object Backend { get; private set; } = null;
|
||||
public int Depth { get; set; } = 0;
|
||||
public bool IsSelected { get; set; } = false;
|
||||
public List<BranchTreeNode> Children { get; private set; } = new List<BranchTreeNode>();
|
||||
|
||||
public bool IsFiltered
|
||||
public Models.FilterMode FilterMode
|
||||
{
|
||||
get => _isFiltered;
|
||||
set => SetProperty(ref _isFiltered, value);
|
||||
get => _filterMode;
|
||||
set => SetProperty(ref _filterMode, value);
|
||||
}
|
||||
|
||||
public bool IsExpanded
|
||||
|
@ -51,7 +50,7 @@ namespace SourceGit.ViewModels
|
|||
get => Backend is Models.Branch b ? b.FriendlyName : null;
|
||||
}
|
||||
|
||||
private bool _isFiltered = false;
|
||||
private Models.FilterMode _filterMode = Models.FilterMode.None;
|
||||
private bool _isExpanded = false;
|
||||
private CornerRadius _cornerRadius = new CornerRadius(4);
|
||||
|
||||
|
@ -60,18 +59,25 @@ namespace SourceGit.ViewModels
|
|||
public List<BranchTreeNode> Locals => _locals;
|
||||
public List<BranchTreeNode> Remotes => _remotes;
|
||||
|
||||
public Builder(Models.RepositorySettings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
public void Run(List<Models.Branch> branches, List<Models.Remote> remotes, bool bForceExpanded)
|
||||
{
|
||||
var folders = new Dictionary<string, BranchTreeNode>();
|
||||
|
||||
foreach (var remote in remotes)
|
||||
{
|
||||
var path = $"remote/{remote.Name}";
|
||||
var path = $"refs/remotes/{remote.Name}";
|
||||
var node = new BranchTreeNode()
|
||||
{
|
||||
Name = remote.Name,
|
||||
Path = path,
|
||||
Backend = remote,
|
||||
IsExpanded = bForceExpanded || _expanded.Contains(path),
|
||||
FilterMode = _settings.GetHistoriesFilterMode(path, Models.FilterType.RemoteBranchFolder)
|
||||
};
|
||||
|
||||
folders.Add(path, node);
|
||||
|
@ -80,16 +86,15 @@ namespace SourceGit.ViewModels
|
|||
|
||||
foreach (var branch in branches)
|
||||
{
|
||||
var isFiltered = _filters.Contains(branch.FullName);
|
||||
if (branch.IsLocal)
|
||||
{
|
||||
MakeBranchNode(branch, _locals, folders, "local", isFiltered, bForceExpanded);
|
||||
MakeBranchNode(branch, _locals, folders, "refs/heads", bForceExpanded);
|
||||
}
|
||||
else
|
||||
{
|
||||
var remote = _remotes.Find(x => x.Name == branch.Remote);
|
||||
if (remote != null)
|
||||
MakeBranchNode(branch, remote.Children, folders, $"remote/{remote.Name}", isFiltered, bForceExpanded);
|
||||
MakeBranchNode(branch, remote.Children, folders, $"refs/remotes/{remote.Name}", bForceExpanded);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,42 +103,36 @@ namespace SourceGit.ViewModels
|
|||
SortNodes(_remotes);
|
||||
}
|
||||
|
||||
public void SetFilters(AvaloniaList<string> filters)
|
||||
{
|
||||
_filters.AddRange(filters);
|
||||
}
|
||||
|
||||
public void CollectExpandedNodes(List<BranchTreeNode> nodes, bool isLocal)
|
||||
{
|
||||
CollectExpandedNodes(nodes, isLocal ? "local" : "remote");
|
||||
}
|
||||
|
||||
private void CollectExpandedNodes(List<BranchTreeNode> nodes, string prefix)
|
||||
public void CollectExpandedNodes(List<BranchTreeNode> nodes)
|
||||
{
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
if (node.Backend is Models.Branch)
|
||||
continue;
|
||||
|
||||
var path = prefix + "/" + node.Name;
|
||||
if (node.IsExpanded)
|
||||
_expanded.Add(path);
|
||||
_expanded.Add(node.Path);
|
||||
|
||||
CollectExpandedNodes(node.Children, path);
|
||||
CollectExpandedNodes(node.Children);
|
||||
}
|
||||
}
|
||||
|
||||
private void MakeBranchNode(Models.Branch branch, List<BranchTreeNode> roots, Dictionary<string, BranchTreeNode> folders, string prefix, bool isFiltered, bool bForceExpanded)
|
||||
private void MakeBranchNode(Models.Branch branch, List<BranchTreeNode> roots, Dictionary<string, BranchTreeNode> folders, string prefix, bool bForceExpanded)
|
||||
{
|
||||
var fullpath = $"{prefix}/{branch.Name}";
|
||||
var branchFilterType = branch.IsLocal ? Models.FilterType.LocalBranch : Models.FilterType.RemoteBranch;
|
||||
var folderFilterType = branch.IsLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder;
|
||||
|
||||
var sepIdx = branch.Name.IndexOf('/', StringComparison.Ordinal);
|
||||
if (sepIdx == -1 || branch.IsDetachedHead)
|
||||
{
|
||||
roots.Add(new BranchTreeNode()
|
||||
{
|
||||
Name = branch.Name,
|
||||
Path = fullpath,
|
||||
Backend = branch,
|
||||
IsExpanded = false,
|
||||
IsFiltered = isFiltered,
|
||||
FilterMode = _settings.GetHistoriesFilterMode(fullpath, branchFilterType),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -156,7 +155,9 @@ namespace SourceGit.ViewModels
|
|||
lastFolder = new BranchTreeNode()
|
||||
{
|
||||
Name = name,
|
||||
Path = folder,
|
||||
IsExpanded = bForceExpanded || branch.IsCurrent || _expanded.Contains(folder),
|
||||
FilterMode = _settings.GetHistoriesFilterMode(folder, folderFilterType),
|
||||
};
|
||||
roots.Add(lastFolder);
|
||||
folders.Add(folder, lastFolder);
|
||||
|
@ -166,7 +167,9 @@ namespace SourceGit.ViewModels
|
|||
var cur = new BranchTreeNode()
|
||||
{
|
||||
Name = name,
|
||||
Path = folder,
|
||||
IsExpanded = bForceExpanded || branch.IsCurrent || _expanded.Contains(folder),
|
||||
FilterMode = _settings.GetHistoriesFilterMode(folder, folderFilterType),
|
||||
};
|
||||
lastFolder.Children.Add(cur);
|
||||
folders.Add(folder, cur);
|
||||
|
@ -179,10 +182,11 @@ namespace SourceGit.ViewModels
|
|||
|
||||
lastFolder?.Children.Add(new BranchTreeNode()
|
||||
{
|
||||
Name = Path.GetFileName(branch.Name),
|
||||
Name = System.IO.Path.GetFileName(branch.Name),
|
||||
Path = fullpath,
|
||||
Backend = branch,
|
||||
IsExpanded = false,
|
||||
IsFiltered = isFiltered,
|
||||
FilterMode = _settings.GetHistoriesFilterMode(fullpath, branchFilterType),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -203,10 +207,10 @@ namespace SourceGit.ViewModels
|
|||
SortNodes(node.Children);
|
||||
}
|
||||
|
||||
private readonly Models.RepositorySettings _settings = null;
|
||||
private readonly List<BranchTreeNode> _locals = new List<BranchTreeNode>();
|
||||
private readonly List<BranchTreeNode> _remotes = new List<BranchTreeNode>();
|
||||
private readonly HashSet<string> _expanded = new HashSet<string>();
|
||||
private readonly List<string> _filters = new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
var b = _repo.Branches.Find(x => x.IsLocal && x.Name == Branch);
|
||||
if (b != null)
|
||||
_repo.AutoAddBranchFilterPostCheckout(b);
|
||||
_repo.UpdateHistoriesFilterAfterCheckout(b);
|
||||
|
||||
_repo.MarkBranchesDirtyManually();
|
||||
_repo.SetWatcherEnabled(true);
|
||||
|
|
|
@ -127,7 +127,7 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
if (CheckoutAfterCreated)
|
||||
{
|
||||
_repo.AutoAddBranchFilterPostCheckout(new Models.Branch()
|
||||
_repo.UpdateHistoriesFilterAfterCheckout(new Models.Branch()
|
||||
{
|
||||
FullName = $"refs/heads/{_name}",
|
||||
Upstream = BasedOn is Models.Branch { IsLocal: false } remoteBranch ? remoteBranch.FullName : string.Empty,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.ViewModels
|
||||
|
@ -57,10 +58,17 @@ namespace SourceGit.ViewModels
|
|||
var succ = Commands.Branch.Rename(_repo.FullPath, Target.Name, _name);
|
||||
CallUIThread(() =>
|
||||
{
|
||||
if (succ && _repo.Settings.Filters.Contains(oldName))
|
||||
if (succ)
|
||||
{
|
||||
_repo.Settings.Filters.Remove(oldName);
|
||||
_repo.Settings.Filters.Add($"refs/heads/{_name}");
|
||||
foreach (var filter in _repo.Settings.HistoriesFilters)
|
||||
{
|
||||
if (filter.Type == Models.FilterType.LocalBranch &&
|
||||
filter.Pattern.Equals(oldName, StringComparison.Ordinal))
|
||||
{
|
||||
filter.Pattern = $"refs/heads/{_name}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_repo.MarkBranchesDirtyManually();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -455,13 +456,9 @@ namespace SourceGit.ViewModels
|
|||
_hasAllowedSignersFile = !string.IsNullOrEmpty(allowedSignersFile);
|
||||
});
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
RefreshBranches();
|
||||
RefreshTags();
|
||||
RefreshCommits();
|
||||
});
|
||||
|
||||
Task.Run(RefreshBranches);
|
||||
Task.Run(RefreshTags);
|
||||
Task.Run(RefreshCommits);
|
||||
Task.Run(RefreshSubmodules);
|
||||
Task.Run(RefreshWorktrees);
|
||||
Task.Run(RefreshWorkingCopyChanges);
|
||||
|
@ -587,18 +584,6 @@ namespace SourceGit.ViewModels
|
|||
Filter = string.Empty;
|
||||
}
|
||||
|
||||
public void ClearHistoriesFilter()
|
||||
{
|
||||
_settings.Filters.Clear();
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
RefreshBranches();
|
||||
RefreshTags();
|
||||
RefreshCommits();
|
||||
});
|
||||
}
|
||||
|
||||
public void ClearSearchCommitFilter()
|
||||
{
|
||||
SearchCommitFilter = string.Empty;
|
||||
|
@ -653,12 +638,8 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
if (_watcher == null)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
RefreshBranches();
|
||||
RefreshCommits();
|
||||
});
|
||||
|
||||
Task.Run(RefreshBranches);
|
||||
Task.Run(RefreshCommits);
|
||||
Task.Run(RefreshWorkingCopyChanges);
|
||||
Task.Run(RefreshWorktrees);
|
||||
}
|
||||
|
@ -696,53 +677,48 @@ namespace SourceGit.ViewModels
|
|||
NavigateToCommit(_currentBranch.Head);
|
||||
}
|
||||
|
||||
public void AutoAddBranchFilterPostCheckout(Models.Branch local)
|
||||
public void ClearHistoriesFilter()
|
||||
{
|
||||
if (_settings.Filters.Count == 0 || _settings.Filters.Contains(local.FullName))
|
||||
return;
|
||||
_settings.HistoriesFilters.Clear();
|
||||
|
||||
var hasLeft = false;
|
||||
foreach (var b in _branches)
|
||||
{
|
||||
if (!b.FullName.Equals(local.FullName, StringComparison.Ordinal) &&
|
||||
!b.FullName.Equals(local.Upstream, StringComparison.Ordinal) &&
|
||||
!_settings.Filters.Contains(b.FullName))
|
||||
{
|
||||
hasLeft = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var builder = BuildBranchTree(_branches, _remotes);
|
||||
LocalBranchTrees = builder.Locals;
|
||||
RemoteBranchTrees = builder.Remotes;
|
||||
foreach (var tag in VisibleTags)
|
||||
tag.FilterMode = Models.FilterMode.None;
|
||||
|
||||
if (!hasLeft)
|
||||
_settings.Filters.Clear();
|
||||
else if (string.IsNullOrEmpty(local.Upstream) || _settings.Filters.Contains(local.Upstream))
|
||||
_settings.Filters.Add(local.FullName);
|
||||
else
|
||||
_settings.Filters.AddRange([local.FullName, local.Upstream]);
|
||||
Task.Run(RefreshCommits);
|
||||
}
|
||||
|
||||
public void UpdateFilters(List<string> filters, bool toggle)
|
||||
public void UpdateHistoriesFilterAfterCheckout(Models.Branch local)
|
||||
{
|
||||
var changed = false;
|
||||
if (toggle)
|
||||
var hasIncludedBranch = false;
|
||||
foreach (var filter in _settings.HistoriesFilters)
|
||||
{
|
||||
foreach (var filter in filters)
|
||||
if (filter.Type == Models.FilterType.LocalBranch)
|
||||
{
|
||||
if (!_settings.Filters.Contains(filter))
|
||||
{
|
||||
_settings.Filters.Add(filter);
|
||||
changed = true;
|
||||
}
|
||||
if (filter.Pattern.Equals(local.FullName, StringComparison.Ordinal))
|
||||
return;
|
||||
|
||||
hasIncludedBranch |= filter.Mode == Models.FilterMode.Included;
|
||||
}
|
||||
else if (filter.Type == Models.FilterType.LocalBranchFolder)
|
||||
{
|
||||
if (local.FullName.StartsWith(filter.Pattern, StringComparison.Ordinal))
|
||||
return;
|
||||
|
||||
hasIncludedBranch |= filter.Mode == Models.FilterMode.Included;
|
||||
}
|
||||
else if (filter.Type == Models.FilterType.RemoteBranch || filter.Type == Models.FilterType.RemoteBranchFolder)
|
||||
{
|
||||
hasIncludedBranch |= filter.Mode == Models.FilterMode.Included;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var filter in filters)
|
||||
changed |= _settings.Filters.Remove(filter);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
Task.Run(RefreshCommits);
|
||||
if (!hasIncludedBranch)
|
||||
return;
|
||||
|
||||
_settings.UpdateHistoriesFilter(local.FullName, Models.FilterType.LocalBranch, Models.FilterMode.Included);
|
||||
}
|
||||
|
||||
public void StashAll(bool autoStart)
|
||||
|
@ -834,7 +810,7 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
var tags = new Commands.QueryTags(_fullpath).Result();
|
||||
foreach (var tag in tags)
|
||||
tag.IsFiltered = _settings.Filters.Contains(tag.Name);
|
||||
tag.FilterMode = _settings.GetHistoriesFilterMode(tag.Name, Models.FilterType.Tag);
|
||||
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
|
@ -847,49 +823,21 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
Dispatcher.UIThread.Invoke(() => _histories.IsLoading = true);
|
||||
|
||||
var limits = $"-{Preference.Instance.MaxHistoryCommits} ";
|
||||
var builder = new StringBuilder();
|
||||
builder.Append($"-{Preference.Instance.MaxHistoryCommits} ");
|
||||
if (_enableReflog)
|
||||
limits += "--reflog ";
|
||||
builder.Append("--reflog ");
|
||||
if (_enableFirstParentInHistories)
|
||||
limits += "--first-parent ";
|
||||
builder.Append("--first-parent ");
|
||||
|
||||
var validFilters = new List<string>();
|
||||
foreach (var filter in _settings.Filters)
|
||||
{
|
||||
if (filter.StartsWith("refs/", StringComparison.Ordinal))
|
||||
{
|
||||
if (_branches.FindIndex(x => x.FullName == filter) >= 0)
|
||||
validFilters.Add(filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_tags.FindIndex(t => t.Name == filter) >= 0)
|
||||
validFilters.Add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (validFilters.Count > 0)
|
||||
{
|
||||
limits += string.Join(" ", validFilters);
|
||||
|
||||
if (_settings.Filters.Count != validFilters.Count)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
_settings.Filters.Clear();
|
||||
_settings.Filters.AddRange(validFilters);
|
||||
});
|
||||
}
|
||||
}
|
||||
var invalidFilters = new List<Models.Filter>();
|
||||
var filters = _settings.BuildHistoriesFilter();
|
||||
if (string.IsNullOrEmpty(filters))
|
||||
builder.Append("--branches --remotes --tags");
|
||||
else
|
||||
{
|
||||
if (_settings.Filters.Count != 0)
|
||||
Dispatcher.UIThread.Invoke(() => _settings.Filters.Clear());
|
||||
builder.Append(filters);
|
||||
|
||||
limits += "--exclude=refs/stash --all";
|
||||
}
|
||||
|
||||
var commits = new Commands.QueryCommits(_fullpath, limits).Result();
|
||||
var commits = new Commands.QueryCommits(_fullpath, builder.ToString()).Result();
|
||||
var graph = Models.CommitGraph.Parse(commits, _enableFirstParentInHistories);
|
||||
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
|
@ -2061,13 +2009,11 @@ namespace SourceGit.ViewModels
|
|||
|
||||
private BranchTreeNode.Builder BuildBranchTree(List<Models.Branch> branches, List<Models.Remote> remotes)
|
||||
{
|
||||
var builder = new BranchTreeNode.Builder();
|
||||
builder.SetFilters(_settings.Filters);
|
||||
|
||||
var builder = new BranchTreeNode.Builder(_settings);
|
||||
if (string.IsNullOrEmpty(_filter))
|
||||
{
|
||||
builder.CollectExpandedNodes(_localBranchTrees, true);
|
||||
builder.CollectExpandedNodes(_remoteBranchTrees, false);
|
||||
builder.CollectExpandedNodes(_localBranchTrees);
|
||||
builder.CollectExpandedNodes(_remoteBranchTrees);
|
||||
builder.Run(branches, remotes, false);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -22,16 +22,6 @@ namespace SourceGit.ViewModels
|
|||
get => Tag == null;
|
||||
}
|
||||
|
||||
public bool IsFiltered
|
||||
{
|
||||
get => Tag?.IsFiltered ?? false;
|
||||
set
|
||||
{
|
||||
if (Tag != null)
|
||||
Tag.IsFiltered = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsExpanded
|
||||
{
|
||||
get => _isExpanded;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue