Skip to content

Commit

Permalink
Remove RevisionNodeFlags from data grid (gitextensions#10130)
Browse files Browse the repository at this point in the history
Simplify (and a minor optimization) the code when loading revisions.
RevisionNodeFlags has information that is already available in the
GitRevisions, no need to pass that info again.

Set HasNotes after revisions are loaded, that is not required when
displaying a revisions.
  • Loading branch information
gerhardol committed Sep 3, 2022
1 parent e392854 commit bbab8ab
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,8 @@ void DrawItem()
int centerX = g.RenderingOrigin.X + (int)((currentRow.GetCurrentRevisionLane() + 0.5) * LaneWidth);
Rectangle nodeRect = new(centerX - (NodeDimension / 2), centerY - (NodeDimension / 2), NodeDimension, NodeDimension);

bool square = currentRow.Revision.HasRef;
bool hasOutline = currentRow.Revision.IsCheckedOut;
bool square = currentRow.Revision.GitRevision.Refs.Count > 0;
bool hasOutline = currentRow.Revision.GitRevision.ObjectId == _revisionGraph.HeadId;

Brush brush = GetBrushForLaneInfo(currentRowRevisionLaneInfo, currentRow.Revision.IsRelative);
if (square)
Expand Down
22 changes: 18 additions & 4 deletions GitUI/UserControls/RevisionGrid/Graph/RevisionGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ public void LoadingCompleted()

public int Count => _nodes.Count;

public bool OnlyFirstParent { get; set; }
public ObjectId HeadId { get; set; }

/// <summary>
/// Checks whether the given hash is present in the graph.
/// </summary>
Expand Down Expand Up @@ -177,14 +180,25 @@ public void HighlightBranch(ObjectId id)
}
}

/// <summary>
/// Set HasNotes for all GitRevisions (marking Notes as fetched).
/// This is used when no Git Notes at all exist and notes never need to be retrieved.
/// </summary>
public void SetHasNotesForRevisions()
{
foreach (RevisionGraphRevision revision in _nodes)
{
revision.GitRevision.HasNotes = true;
}
}

/// <summary>
/// Add a single revision from the git log to the graph, including segments to parents.
/// </summary>
/// <param name="revision">The revision to add.</param>
/// <param name="types">The graph node flags.</param>
/// <param name="insertScore">Insert the (artificial) revision before the node with this score.</param>
/// <param name="insertRange">Number of scores "reserved" in the list when inserting.</param>
public void Add(GitRevision revision, RevisionNodeFlags types, int? insertScore = null, int insertRange = 0)
public void Add(GitRevision revision, int? insertScore = null, int insertRange = 0)
{
// The commits are sorted by the score (not contiuous numbering there may be gaps)
// This commit will be ordered after existing, _maxScore is a preliminary score
Expand Down Expand Up @@ -233,7 +247,7 @@ public void Add(GitRevision revision, RevisionNodeFlags types, int? insertScore

// This revision may have been added as a parent before. Probably only the ObjectId is known. Set all the other properties.
revisionGraphRevision.GitRevision = revision;
revisionGraphRevision.ApplyFlags(types);
revisionGraphRevision.ApplyFlags(isCheckedOut: HeadId == revision.ObjectId);

// Build the revisions parent/child structure. The parents need to added here. The child structure is kept in synch in
// the RevisionGraphRevision class.
Expand Down Expand Up @@ -265,7 +279,7 @@ public void Add(GitRevision revision, RevisionNodeFlags types, int? insertScore
revisionGraphRevision.AddParent(parentRevisionGraphRevision, out int newMaxScore);
_maxScore = Math.Max(_maxScore, newMaxScore);

if (types.HasFlag(RevisionNodeFlags.OnlyFirstParent))
if (OnlyFirstParent)
{
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,12 @@ public RevisionGraphRevision(ObjectId objectId, int guessScore)
Score = guessScore;
}

public void ApplyFlags(RevisionNodeFlags types)
public void ApplyFlags(bool isCheckedOut)
{
IsRelative |= (types & RevisionNodeFlags.CheckedOut) != 0;
HasRef = (types & RevisionNodeFlags.HasRef) != 0;
IsCheckedOut = (types & RevisionNodeFlags.CheckedOut) != 0;
IsRelative |= isCheckedOut;
}

public bool IsRelative { get; set; }
public bool HasRef { get; set; }
public bool IsCheckedOut { get; set; }

/// <summary>
/// The score is used to order the revisions in topo-order. The initial score will be assigned when a revision is loaded
Expand Down
14 changes: 2 additions & 12 deletions GitUI/UserControls/RevisionGrid/RevisionDataGridView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,6 @@

namespace GitUI.UserControls.RevisionGrid
{
[Flags]
public enum RevisionNodeFlags
{
None = 0,
CheckedOut = 1,
HasRef = 2,
OnlyFirstParent = 4
}

public sealed partial class RevisionDataGridView : DataGridView
{
private const int BackgroundThreadUpdatePeriod = 25;
Expand Down Expand Up @@ -321,11 +312,10 @@ private void OnCellPainting(object? sender, DataGridViewCellPaintingEventArgs e)
/// Update visible rows if needed.
/// </summary>
/// <param name="revision">The revision to add.</param>
/// <param name="types">The graph node flags.</param>
/// <param name="insertWithMatch">Insert the (artificial) revision with the first match in headParents or first if no match found (or headParents is null).</param>
/// <param name="insertRange">Number of scores "reserved" in the list when inserting.</param>
/// <param name="parents">Parent ids for the revision to find (and insert before).</param>
public void Add(GitRevision revision, RevisionNodeFlags types = RevisionNodeFlags.None, bool insertWithMatch = false, int insertRange = 0, IEnumerable<ObjectId>? parents = null)
public void Add(GitRevision revision, bool insertWithMatch = false, int insertRange = 0, IEnumerable<ObjectId>? parents = null)
{
// Where to insert the revision, null is last
int? insertScore = null;
Expand Down Expand Up @@ -358,7 +348,7 @@ public void Add(GitRevision revision, RevisionNodeFlags types = RevisionNodeFlag
}
}

_revisionGraph.Add(revision, types, insertScore, insertRange);
_revisionGraph.Add(revision, insertScore, insertRange);
if (ToBeSelectedObjectIds.Contains(revision.ObjectId))
{
++_loadedToBeSelectedRevisionsCount;
Expand Down
43 changes: 15 additions & 28 deletions GitUI/UserControls/RevisionGrid/RevisionGridControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -884,8 +884,6 @@ public void PerformRefreshRevisions(Func<RefsFilter, IReadOnlyList<IGitRef>> get
ILookup<ObjectId, IGitRef> refsByObjectId = null;
bool firstRevisionReceived = false;
bool headIsHandled = false;
bool hasAnyNotes = false;
bool onlyFirstParent = false;

// getRefs (refreshing from Browse) is Lazy already, but not from RevGrid (updating filters etc)
Lazy<IReadOnlyList<IGitRef>> getUnfilteredRefs = new(() => (getRefs ?? capturedModule.GetRefs)(RefsFilter.NoFilter));
Expand Down Expand Up @@ -959,9 +957,8 @@ public void PerformRefreshRevisions(Func<RefsFilter, IReadOnlyList<IGitRef>> get
UpdateSelectedRef(capturedModule, getUnfilteredRefs.Value, headRef);
_gridView.ToBeSelectedObjectIds = GetToBeSelectedRevisions(newCurrentCheckout, currentlySelectedObjectIds);
// optimize for no notes at all
hasAnyNotes = AppSettings.ShowGitNotes && getUnfilteredRefs.Value.Any(i => i.CompleteName == GitRefName.RefsNotesPrefix);
onlyFirstParent = _filterInfo.RefFilterOptions.HasFlag(RefFilterOptions.FirstParent);
_gridView._revisionGraph.OnlyFirstParent = _filterInfo.RefFilterOptions.HasFlag(RefFilterOptions.FirstParent);
_gridView._revisionGraph.HeadId = CurrentCheckout;
// Allow add revisions to the grid
semaphoreUpdateGrid.Release();
Expand Down Expand Up @@ -1147,44 +1144,23 @@ void OnRevisionRead(GitRevision revision)
if (!firstRevisionReceived)
{
// Wait for refs,CurrentCheckout to be available
this.InvokeAsync(() => { ShowLoading(showSpinner: false); }).FileAndForget();
semaphoreUpdateGrid.Wait(cancellationToken);
firstRevisionReceived = true;
this.InvokeAsync(() => { ShowLoading(showSpinner: false); }).FileAndForget();
}

RevisionNodeFlags flags = RevisionNodeFlags.None;

if (!headIsHandled && (revision.ObjectId.Equals(CurrentCheckout) || CurrentCheckout is null))
{
// Insert worktree/index before HEAD (CurrentCheckout)
// If grid is filtered and HEAD not visible, insert artificial in OnRevisionReadCompleted()
headIsHandled = true;
AddArtificialRevisions();
if (CurrentCheckout is not null)
{
flags = RevisionNodeFlags.CheckedOut;
}
}

// Look up any refs associated with this revision
revision.Refs = refsByObjectId[revision.ObjectId].AsReadOnlyList();
if (revision.Refs.Count != 0)
{
flags |= RevisionNodeFlags.HasRef;
}

if (onlyFirstParent)
{
flags |= RevisionNodeFlags.OnlyFirstParent;
}

if (!hasAnyNotes)
{
// No notes at all in this repo
revision.HasNotes = true;
}

_gridView.Add(revision, flags);
_gridView.Add(revision);

return;
}
Expand Down Expand Up @@ -1349,6 +1325,17 @@ void OnRevisionReadCompleted()
RevisionsLoaded?.Invoke(this, new RevisionLoadEventArgs(this, UICommands, getUnfilteredRefs, forceRefresh));
HighlightRevisionsByAuthor(GetSelectedRevisions());
await TaskScheduler.Default;
// optimize for no notes at all in repo
// Improvement: set .HasNotes for commits not included in git-notes
bool hasAnyNotes = AppSettings.ShowGitNotes && getUnfilteredRefs.Value.Any(i => i.CompleteName == GitRefName.RefsNotesPrefix);
if (!hasAnyNotes)
{
// No notes at all in this repo
_gridView._revisionGraph.SetHasNotesForRevisions();
}
if (ShowBuildServerInfo)
{
await _buildServerWatcher.LaunchBuildServerInfoFetchOperationAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ public void Setup()
_revisionGraph = new RevisionGraph();

GitRevision revision = new(ObjectId.Random());
_revisionGraph.HeadId = revision.ObjectId;

// Mark the first revision as the current checkout
_revisionGraph.Add(revision, RevisionNodeFlags.CheckedOut);
_revisionGraph.Add(revision);
}

[Test, Timeout(10 /*min*/ * 60 /*s*/ * 1000 /*ms*/)]
Expand Down Expand Up @@ -84,7 +85,7 @@ private void LoadRandomRevisions()
revision.ParentIds = new ObjectId[] { randomRevision1.ObjectId, randomRevision2.ObjectId };
}

_revisionGraph.Add(revision, RevisionNodeFlags.None);
_revisionGraph.Add(revision);

randomRevisions.Add(revision);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ public void Setup()
foreach (var revision in Revisions)
{
// Mark the first revision as the current checkout
_revisionGraph.Add(revision, _revisionGraph.Count == 0 ? RevisionNodeFlags.CheckedOut : RevisionNodeFlags.None);
if (_revisionGraph.Count == 0)
{
_revisionGraph.HeadId = revision.ObjectId;
}

_revisionGraph.Add(revision);
}
}

Expand Down Expand Up @@ -82,20 +87,20 @@ public void ShouldReorderInTopoOrder()
commit1.ParentIds = new ObjectId[] { commit2.ObjectId };
commit2.ParentIds = new ObjectId[] { _revisionGraph.GetNodeForRow(4).Objectid };

_revisionGraph.Add(commit2, RevisionNodeFlags.None); // This commit is now dangling
_revisionGraph.Add(commit2); // This commit is now dangling

_revisionGraph.CacheTo(_revisionGraph.Count, _revisionGraph.Count);
Assert.IsTrue(_revisionGraph.GetTestAccessor().ValidateTopoOrder());

_revisionGraph.Add(commit1, RevisionNodeFlags.None); // Add the connecting commit
_revisionGraph.Add(commit1); // Add the connecting commit

_revisionGraph.CacheTo(_revisionGraph.Count, _revisionGraph.Count);
Assert.IsTrue(_revisionGraph.GetTestAccessor().ValidateTopoOrder());

// Add a new head
GitRevision newHead = new(ObjectId.Random());
newHead.ParentIds = new ObjectId[] { _revisionGraph.GetNodeForRow(0).Objectid };
_revisionGraph.Add(newHead, RevisionNodeFlags.None); // Add commit that has the current top node as parent.
_revisionGraph.Add(newHead); // Add commit that has the current top node as parent.

_revisionGraph.CacheTo(_revisionGraph.Count, _revisionGraph.Count); // Call to cache fix the order
Assert.IsTrue(_revisionGraph.GetTestAccessor().ValidateTopoOrder());
Expand Down Expand Up @@ -129,9 +134,9 @@ public void DetachedSingleRevision()
GitRevision commit3 = new(ObjectId.Random());
commit1.ParentIds = new ObjectId[] { commit3.ObjectId };

_revisionGraph.Add(commit1, RevisionNodeFlags.None);
_revisionGraph.Add(commit2, RevisionNodeFlags.None);
_revisionGraph.Add(commit3, RevisionNodeFlags.None);
_revisionGraph.Add(commit1);
_revisionGraph.Add(commit2);
_revisionGraph.Add(commit3);

_revisionGraph.CacheTo(_revisionGraph.Count, _revisionGraph.Count);

Expand Down

0 comments on commit bbab8ab

Please sign in to comment.