Skip to content

Commit

Permalink
BlameControl: cancellation token for git-blame (#9816)
Browse files Browse the repository at this point in the history
git-blame may require considerable time, the git executable
must be cancelable.

Clear the blame viewer when processing a new file.
Make the async Clear in FileViewer public.

Cancellation token for LoadBlame
Missing for RevFileTree (and FileHistory), existing for RevDiff
Return the async Task for the Blame.
  • Loading branch information
gerhardol committed Jan 27, 2022
1 parent 1dc9bba commit 3f7d2b3
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 44 deletions.
10 changes: 8 additions & 2 deletions GitCommands/Git/GitModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3260,7 +3260,7 @@ public IEnumerable<INamedGitItem> GetTree(ObjectId? commitId, bool full)
return _gitTreeParser.Parse(tree);
}

public GitBlame Blame(string? fileName, string from, Encoding encoding, string? lines = null)
public GitBlame Blame(string? fileName, string from, Encoding encoding, string? lines = null, CancellationToken cancellationToken = default)
{
GitArgumentBuilder args = new("blame")
{
Expand All @@ -3275,7 +3275,13 @@ public GitBlame Blame(string? fileName, string from, Encoding encoding, string?
fileName.ToPosixPath().Quote()
};

var output = _gitExecutable.GetOutput(args, cache: GitCommandCache, outputEncoding: LosslessEncoding);
ExecutionResult result = _gitExecutable.Execute(
args,
cache: GitCommandCache,
outputEncoding: LosslessEncoding,
cancellationToken: cancellationToken);

var output = result.StandardOutput;

try
{
Expand Down
2 changes: 1 addition & 1 deletion GitUI/CommandsDialogs/FormBlame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public FormBlame(GitUICommands commands, string fileName, GitRevision? revision,

FileName = fileName;

blameControl1.LoadBlame(revision ?? Module.GetRevision(), null, fileName, null, null, Module.FilesEncoding, initialLine);
_ = blameControl1.LoadBlameAsync(revision ?? Module.GetRevision(), null, fileName, null, null, Module.FilesEncoding, initialLine);
blameControl1.ConfigureRepositoryHostPlugin(PluginRegistry.TryGetGitHosterForModule(Module));
}

Expand Down
2 changes: 1 addition & 1 deletion GitUI/CommandsDialogs/FormFileHistory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ private void UpdateSelectedFileViewers(bool force = false)

if (tabControl1.SelectedTab == BlameTab)
{
Blame.LoadBlame(revision, children, fileName, RevisionGrid, BlameTab, Diff.Encoding, force: force);
_ = Blame.LoadBlameAsync(revision, children, fileName, RevisionGrid, BlameTab, Diff.Encoding, force: force, cancellationToken: _viewChangesSequence.Next());
}
else if (tabControl1.SelectedTab == ViewTab)
{
Expand Down
32 changes: 16 additions & 16 deletions GitUI/CommandsDialogs/RevisionDiffControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -476,14 +476,15 @@ private void ResetSelectedItemsTo(bool actsAsChild)
RequestRefresh();
}

private void BlameSelectedFileDiff(int? line = null)
private async Task ShowSelectedFileBlameAsync(int? line = null)
{
BlameControl.Visible = true;
DiffText.Visible = false;
GitRevision rev = DiffFiles.SelectedItem.SecondRevision.IsArtificial
? _revisionGrid.GetActualRevision(_revisionGrid.CurrentCheckout)
: DiffFiles.SelectedItem.SecondRevision;
BlameControl.LoadBlame(rev, children: null, DiffFiles.SelectedItem.Item.Name, _revisionGrid, controlToMask: null, DiffText.Encoding, line, cancellationToken: _viewChangesSequence.Next());
await BlameControl.LoadBlameAsync(rev, children: null, DiffFiles.SelectedItem.Item.Name, _revisionGrid,
controlToMask: null, DiffText.Encoding, line, cancellationToken: _viewChangesSequence.Next());
}

private async Task ShowSelectedFileDiffAsync()
Expand All @@ -495,12 +496,16 @@ await DiffText.ViewChangesAsync(DiffFiles.SelectedItem,
cancellationToken: _viewChangesSequence.Next());
}

/// <summary>
/// Show selected item as diff or blame
/// </summary>
private void ShowSelectedFile(int? line = null) =>
ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
await (DiffText.Visible ? ShowSelectedFileDiffAsync() : ShowSelectedFileBlameAsync(line))).FileAndForget();

private void DiffFiles_SelectedIndexChanged(object sender, EventArgs e)
{
ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
{
await ShowSelectedFileDiffAsync();
}).FileAndForget();
ThreadHelper.JoinableTaskFactory.RunAsync(ShowSelectedFileDiffAsync).FileAndForget();
}

private void DiffFiles_DoubleClick(object sender, EventArgs e)
Expand All @@ -513,11 +518,7 @@ private void DiffFiles_DoubleClick(object sender, EventArgs e)

if (AppSettings.OpenSubmoduleDiffInSeparateWindow && item.Item.IsSubmodule)
{
ThreadHelper.JoinableTaskFactory.RunAsync(
async () =>
{
await DiffFiles.OpenSubmoduleAsync();
});
ThreadHelper.JoinableTaskFactory.RunAsync(DiffFiles.OpenSubmoduleAsync);
}
else
{
Expand All @@ -535,10 +536,7 @@ private void DiffFiles_DataSourceChanged(object sender, EventArgs e)

private void DiffText_ExtraDiffArgumentsChanged(object sender, EventArgs e)
{
ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
{
await ShowSelectedFileDiffAsync();
}).FileAndForget();
ThreadHelper.JoinableTaskFactory.RunAsync(ShowSelectedFileDiffAsync).FileAndForget();
}

private void DiffText_PatchApplied(object sender, EventArgs e)
Expand Down Expand Up @@ -637,7 +635,9 @@ private void blameToolStripMenuItem_Click(object sender, EventArgs e)
{
int? line = DiffText.Visible ? DiffText.CurrentFileLine : null;
blameToolStripMenuItem.Checked = !blameToolStripMenuItem.Checked;
BlameSelectedFileDiff(line);
BlameControl.Visible = blameToolStripMenuItem.Checked;
DiffText.Visible = !blameToolStripMenuItem.Checked;
ShowSelectedFile(line);
return;
}

Expand Down
13 changes: 0 additions & 13 deletions GitUI/CommandsDialogs/RevisionFileTreeControl.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 18 additions & 3 deletions GitUI/CommandsDialogs/RevisionFileTreeControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ private readonly RememberFileContextMenuController _rememberFileContextMenuContr
= RememberFileContextMenuController.Default;
private Action? _refreshGitStatus;
private RevisionGridControl? _revisionGrid;
private readonly CancellationTokenSequence _viewBlameSequence = new();

public RevisionFileTreeControl()
{
Expand Down Expand Up @@ -290,6 +291,21 @@ private string GetShortcutKeyDisplayString(Command cmd)

#endregion

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
_viewBlameSequence.Dispose();
components?.Dispose();
}

base.Dispose(disposing);
}

protected override void OnRuntimeLoad()
{
tvGitTree.ImageList = new ImageList(components)
Expand Down Expand Up @@ -391,8 +407,7 @@ private Task ShowGitItemAsync(GitItem gitItem)
int? line = FileText.Visible ? FileText.CurrentFileLine : null;
BlameControl.Visible = true;
FileText.Visible = false;
BlameControl.LoadBlame(_revision, children: null, gitItem.FileName, _revisionGrid, controlToMask: null, FileText.Encoding, line);
return Task.CompletedTask;
return BlameControl.LoadBlameAsync(_revision, children: null, gitItem.FileName, _revisionGrid, controlToMask: null, FileText.Encoding, line, cancellationToken: _viewBlameSequence.Next());
}

case GitObjectType.Commit:
Expand Down Expand Up @@ -423,7 +438,7 @@ private Task ClearOutputAsync()
{
BlameControl.Visible = false;
FileText.Visible = true;
return FileText.ViewTextAsync("", "");
return FileText.ClearAsync();
}

private void tvGitTree_BeforeExpand(object sender, TreeViewCancelEventArgs e)
Expand Down
18 changes: 13 additions & 5 deletions GitUI/Editor/FileViewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,11 @@ public void SetGitBlameGutter(IEnumerable<GitBlameEntry> gitBlameEntries)
}
}

public void ClearBlameGutter()
{
internalFileViewer.ShowGutterAvatars = false;
}

public void ReloadHotkeys()
{
Hotkeys = HotkeySettingsManager.LoadHotkeys(HotkeySettingsName);
Expand Down Expand Up @@ -649,9 +654,11 @@ string GetFileText()
}
}

public Task ClearAsync() => ViewTextAsync("", "");

public void Clear()
{
ThreadHelper.JoinableTaskFactory.Run(() => ViewTextAsync("", ""));
ThreadHelper.JoinableTaskFactory.Run(() => ClearAsync());
}

/// <summary>
Expand Down Expand Up @@ -863,24 +870,25 @@ long GetFileLength()
}
}

private Task ShowOrDeferAsync(long contentLength, Func<Task> showFunc)
private async Task ShowOrDeferAsync(long contentLength, Func<Task> showFunc)
{
const long maxLength = 5 * 1024 * 1024;

if (contentLength > maxLength)
{
Clear();
await ClearAsync();
Refresh();
_NO_TRANSLATE_lblShowPreview.Text = string.Format(_largeFileSizeWarning.Text, contentLength / (1024d * 1024));
_NO_TRANSLATE_lblShowPreview.Show();
_deferShowFunc = showFunc;
return Task.CompletedTask;
return;
}
else
{
_NO_TRANSLATE_lblShowPreview.Hide();
_deferShowFunc = null;
return showFunc();
await showFunc();
return;
}
}

Expand Down
2 changes: 1 addition & 1 deletion GitUI/GitUIExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static async Task ViewChangesAsync(this FileViewer fileViewer,
return;
}

fileViewer.Clear();
await fileViewer.ClearAsync();
return;
}

Expand Down
10 changes: 8 additions & 2 deletions GitUI/UserControls/BlameControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using GitCommands;
using GitExtUtils;
Expand Down Expand Up @@ -96,7 +97,7 @@ public void HideCommitInfo()
CommitInfo.CommandClicked -= commitInfo_CommandClicked;
}

public void LoadBlame(GitRevision revision, IReadOnlyList<ObjectId>? children, string? fileName, RevisionGridControl? revGrid, Control? controlToMask, Encoding encoding, int? initialLine = null, bool force = false, CancellationToken cancellationToken = default)
public async Task LoadBlameAsync(GitRevision revision, IReadOnlyList<ObjectId>? children, string? fileName, RevisionGridControl? revGrid, Control? controlToMask, Encoding encoding, int? initialLine = null, bool force = false, CancellationToken cancellationToken = default)
{
ObjectId objectId = revision.ObjectId;

Expand All @@ -121,7 +122,12 @@ public void LoadBlame(GitRevision revision, IReadOnlyList<ObjectId>? children, s
? _clickedBlameLine.OriginLineNumber
: initialLine ?? 0;

_blameLoader.LoadAsync(() => _blame = Module.Blame(fileName, objectId.ToString(), encoding),
// Clear the contents of the viewer while loading
BlameAuthor.ClearBlameGutter();
await BlameAuthor.ClearAsync();
await BlameFile.ClearAsync();

await _blameLoader.LoadAsync(cancellationToken => _blame = Module.Blame(fileName, objectId.ToString(), encoding, cancellationToken: cancellationToken),
() => ProcessBlame(fileName, revision, children, controlToMask, line, scrollPos, cancellationToken));
}

Expand Down

0 comments on commit 3f7d2b3

Please sign in to comment.