Skip to content

Commit 6e7989f

Browse files
committed
Merge remote-tracking branch 'upstream/master' into v3-ux
% Conflicts: % GitExtUtils/GitUI/TaskExtensions.cs % GitUI/UserControls/FileStatusList.cs % GitUI/UserControls/RevisionGrid.cs % GitUI/UserControls/RevisionGrid/GitRefListsForRevision.cs % GitUI/UserControls/RevisionGridClasses/CopyContextMenuViewModel.cs % UnitTests/GitUITests/GitUITests.csproj
2 parents 51f4b95 + f68cacc commit 6e7989f

18 files changed

+162
-41
lines changed
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
GitUI.ThreadHelper.ThrowIfNotOnUIThread
1+
[GitUI.ThreadHelper]::ThrowIfNotOnUIThread
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
GitUI.ControlThreadingExtensions.SwitchToMainThreadAsync
1+
[GitUI.ControlThreadingExtensions]::SwitchToMainThreadAsync

Directory.Build.targets

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
</ItemGroup>
66

77
<ItemGroup Condition="'$(EnableVisualStudioThreading)' != 'false'">
8-
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="15.6.46" />
8+
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="15.8.132" />
99
</ItemGroup>
1010

1111
</Project>

Externals/Git.hub

GitCommands/RevisionReader.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ private async Task ExecuteAsync(
6060
string pathFilter,
6161
[CanBeNull] Func<GitRevision, bool> revisionPredicate)
6262
{
63-
ThreadHelper.ThrowIfNotOnUIThread();
63+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
6464

6565
var token = _cancellationTokenSequence.Next();
6666

GitExtUtils/GitExtUtils.csproj

-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
<Compile Include="GitUI\ControlThreadingExtensions.cs" />
5353
<Compile Include="GitUI\DpiUtil.cs" />
5454
<Compile Include="GitUI\TableLayoutPanelExtensions.cs" />
55-
<Compile Include="GitUI\TaskExtensions.cs" />
5655
<Compile Include="GitUI\ThreadHelper.cs" />
5756
<Compile Include="GitUI\UIExtensions.cs" />
5857
<Compile Include="Linq\LinqExtensions.cs" />

GitExtUtils/GitUI/ControlThreadingExtensions.cs

+12
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,16 @@ public static ControlMainThreadAwaitable SwitchToMainThreadAsync(this ToolStripI
2727
{
2828
if (cancellationToken.IsCancellationRequested)
2929
{
30+
#pragma warning disable VSTHRD004 // Await SwitchToMainThreadAsync
3031
return new ControlMainThreadAwaitable(ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken), disposable: null, cancellationToken);
32+
#pragma warning restore VSTHRD004 // Await SwitchToMainThreadAsync
3133
}
3234

3335
if (control.IsDisposed)
3436
{
37+
#pragma warning disable VSTHRD004 // Await SwitchToMainThreadAsync
3538
return new ControlMainThreadAwaitable(ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_preCancelledToken), disposable: null, _preCancelledToken);
39+
#pragma warning restore VSTHRD004 // Await SwitchToMainThreadAsync
3640
}
3741

3842
var disposedCancellationToken = ToolStripItemDisposedCancellationFactory.Instance.GetOrCreateCancellationToken(control);
@@ -43,20 +47,26 @@ public static ControlMainThreadAwaitable SwitchToMainThreadAsync(this ToolStripI
4347
disposedCancellationToken = cancellationTokenSource.Token;
4448
}
4549

50+
#pragma warning disable VSTHRD004 // Await SwitchToMainThreadAsync
4651
var mainThreadAwaiter = ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(disposedCancellationToken);
52+
#pragma warning restore VSTHRD004 // Await SwitchToMainThreadAsync
4753
return new ControlMainThreadAwaitable(mainThreadAwaiter, cancellationTokenSource, disposedCancellationToken);
4854
}
4955

5056
public static ControlMainThreadAwaitable SwitchToMainThreadAsync(this Control control, CancellationToken cancellationToken = default)
5157
{
5258
if (cancellationToken.IsCancellationRequested)
5359
{
60+
#pragma warning disable VSTHRD004 // Await SwitchToMainThreadAsync
5461
return new ControlMainThreadAwaitable(ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken), disposable: null, cancellationToken);
62+
#pragma warning restore VSTHRD004 // Await SwitchToMainThreadAsync
5563
}
5664

5765
if (control.IsDisposed)
5866
{
67+
#pragma warning disable VSTHRD004 // Await SwitchToMainThreadAsync
5968
return new ControlMainThreadAwaitable(ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_preCancelledToken), disposable: null, _preCancelledToken);
69+
#pragma warning restore VSTHRD004 // Await SwitchToMainThreadAsync
6070
}
6171

6272
var disposedCancellationToken = ControlIsDisposedCancellationFactory.Instance.GetOrCreateCancellationToken(control);
@@ -67,7 +77,9 @@ public static ControlMainThreadAwaitable SwitchToMainThreadAsync(this Control co
6777
disposedCancellationToken = cancellationTokenSource.Token;
6878
}
6979

80+
#pragma warning disable VSTHRD004 // Await SwitchToMainThreadAsync
7081
var mainThreadAwaiter = ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(disposedCancellationToken);
82+
#pragma warning restore VSTHRD004 // Await SwitchToMainThreadAsync
7183
return new ControlMainThreadAwaitable(mainThreadAwaiter, cancellationTokenSource, disposedCancellationToken);
7284
}
7385

GitExtensions.ruleset

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
<Rule Id="CA1301" Action="None" />
66
<Rule Id="CA2101" Action="None" />
77
</Rules>
8+
<Rules AnalyzerId="Microsoft.VisualStudio.Threading.Analyzers" RuleNamespace="Microsoft.VisualStudio.Threading.Analyzers">
9+
<Rule Id="VSTHRD010" Action="None" />
10+
<Rule Id="VSTHRD110" Action="None" />
11+
</Rules>
812
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
913
<Rule Id="SA1101" Action="None" />
1014
<Rule Id="SA1116" Action="None" />

GitUI/BranchTreePanel/RepoObjectsTree.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ public void SetBranchFilterer(FilterBranchHelper filterBranchHelper)
150150

151151
public async Task ReloadAsync()
152152
{
153-
ThreadHelper.ThrowIfNotOnUIThread();
153+
await this.SwitchToMainThreadAsync();
154154

155155
var token = CancelBackgroundTasks();
156156
Enabled = false;

GitUI/UserControls/FileStatusList.Designer.cs

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

GitUI/UserControls/FileStatusList.cs

+22-26
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ public sealed partial class FileStatusList : GitModuleControl
3535

3636
private static readonly TimeSpan SelectedIndexChangeThrottleDuration = TimeSpan.FromMilliseconds(50);
3737

38-
[CanBeNull] private static ImageList _images;
39-
4038
private readonly TranslationString _diffWithParent = new TranslationString("Diff with:");
4139
public readonly TranslationString CombinedDiff = new TranslationString("Combined Diff");
4240

@@ -58,14 +56,22 @@ public FileStatusList()
5856
FilterVisible = false;
5957

6058
SelectFirstItemOnSetItems = true;
61-
FileStatusListView.MouseMove += FileStatusListView_MouseMove;
62-
FileStatusListView.MouseDown += FileStatusListView_MouseDown;
6359

64-
const int rowHeight = 18;
60+
FileStatusListView.SmallImageList = CreateImageList();
61+
FileStatusListView.LargeImageList = CreateImageList();
62+
63+
HandleVisibility_NoFilesLabel_FilterComboBox(filesPresent: true);
64+
Controls.SetChildIndex(NoFiles, 0);
65+
NoFiles.Font = new Font(SystemFonts.MessageBoxFont, FontStyle.Italic);
66+
67+
_fullPathResolver = new FullPathResolver(() => Module.WorkingDir);
68+
_revisionTester = new GitRevisionTester(_fullPathResolver);
6569

66-
if (_images == null)
70+
ImageList CreateImageList()
6771
{
68-
_images = new ImageList
72+
const int rowHeight = 18;
73+
74+
return new ImageList
6975
{
7076
ImageSize = DpiUtil.Scale(new Size(16, rowHeight)), // Scale ImageSize and images scale automatically
7177
Images =
@@ -87,28 +93,18 @@ public FileStatusList()
8793
ScaleHeight(Images.FileStatusUnknown) // 14
8894
}
8995
};
90-
}
91-
92-
FileStatusListView.SmallImageList = _images;
93-
FileStatusListView.LargeImageList = _images;
9496

95-
HandleVisibility_NoFilesLabel_FilterComboBox(filesPresent: true);
96-
Controls.SetChildIndex(NoFiles, 0);
97-
NoFiles.Font = new Font(SystemFonts.MessageBoxFont, FontStyle.Italic);
98-
99-
_fullPathResolver = new FullPathResolver(() => Module.WorkingDir);
100-
_revisionTester = new GitRevisionTester(_fullPathResolver);
101-
102-
Bitmap ScaleHeight(Bitmap input)
103-
{
104-
Debug.Assert(input.Height < rowHeight, "Can only increase row height");
105-
var scaled = new Bitmap(input.Width, rowHeight, input.PixelFormat);
106-
using (var g = Graphics.FromImage(scaled))
97+
Bitmap ScaleHeight(Bitmap input)
10798
{
108-
g.DrawImageUnscaled(input, 0, (rowHeight - input.Height) / 2);
109-
}
99+
Debug.Assert(input.Height < rowHeight, "Can only increase row height");
100+
var scaled = new Bitmap(input.Width, rowHeight, input.PixelFormat);
101+
using (var g = Graphics.FromImage(scaled))
102+
{
103+
g.DrawImageUnscaled(input, 0, (rowHeight - input.Height) / 2);
104+
}
110105

111-
return scaled;
106+
return scaled;
107+
}
112108
}
113109
}
114110

GitUI/UserControls/MainThreadScheduler.cs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Reactive.Concurrency;
33
using System.Reactive.Disposables;
44
using System.Threading.Tasks;
5+
using Microsoft.VisualStudio.Threading;
56

67
namespace GitUI.UserControls
78
{

GitUI/UserControls/RevisionGrid/GitRefListsForRevision.cs

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using GitCommands;
45
using GitUIPluginInterfaces;
6+
using JetBrains.Annotations;
57

68
namespace GitUI.UserControls.RevisionGrid
79
{
@@ -12,8 +14,18 @@ internal class GitRefListsForRevision
1214
private readonly IGitRef[] _branchesWithNoIdenticalRemotes;
1315
private readonly IGitRef[] _tags;
1416

15-
public GitRefListsForRevision(GitRevision revision)
17+
public GitRefListsForRevision([NotNull] GitRevision revision)
1618
{
19+
if (revision == null)
20+
{
21+
throw new ArgumentNullException(nameof(revision));
22+
}
23+
24+
if (revision.Refs == null)
25+
{
26+
throw new ArgumentNullException(nameof(revision.Refs));
27+
}
28+
1729
_allBranches = revision.Refs.Where(h => !h.IsTag && (h.IsHead || h.IsRemote)).ToArray();
1830
_localBranches = _allBranches.Where(b => !b.IsRemote).ToArray();
1931
_branchesWithNoIdenticalRemotes = _allBranches.Where(b => !b.IsRemote ||
@@ -40,11 +52,11 @@ public IReadOnlyList<string> GetAllTagNames()
4052
}
4153

4254
/// <summary>
43-
/// Returns the collection of local branches and tags which can be deleted.
55+
/// Returns the collection of branches and tags which can be deleted.
4456
/// </summary>
45-
public IReadOnlyList<IGitRef> GetDeletableLocalRefs(string currentBranch)
57+
public IReadOnlyList<IGitRef> GetDeletableRefs(string currentBranch)
4658
{
47-
return _localBranches.Where(b => b.Name != currentBranch).Union(_tags).ToList();
59+
return _allBranches.Where(b => b.IsRemote || b.Name != currentBranch).Union(_tags).ToArray();
4860
}
4961

5062
/// <summary>

GitUI/UserControls/RevisionGrid/RevisionGridControl.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1176,13 +1176,17 @@ private void OnGridViewKeyUp(object sender, KeyEventArgs e)
11761176
case Keys.Delete:
11771177
{
11781178
InitiateRefAction(
1179-
new GitRefListsForRevision(selectedRevision).GetDeletableLocalRefs(Module.GetSelectedBranch()),
1179+
new GitRefListsForRevision(selectedRevision).GetDeletableRefs(Module.GetSelectedBranch()),
11801180
gitRef =>
11811181
{
11821182
if (gitRef.IsTag)
11831183
{
11841184
UICommands.StartDeleteTagDialog(this, gitRef.Name);
11851185
}
1186+
else if (gitRef.IsRemote)
1187+
{
1188+
UICommands.StartDeleteRemoteBranchDialog(this, gitRef.Name);
1189+
}
11861190
else
11871191
{
11881192
UICommands.StartDeleteBranchDialog(this, gitRef.Name);

UnitTests/GitUITests/GitUITests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
<Compile Include="Hotkey\HotkeySettingsManagerFixture.cs" />
8585
<Compile Include="Properties\AssemblyInfo.cs" />
8686
<Compile Include="UserControls\RepoStateVisualiserTests.cs" />
87+
<Compile Include="UserControls\RevisionGrid\GitRefListsForRevisionTests.cs" />
8788
<Compile Include="UserManual\SingleHtmlUserManualFixture.cs" />
8889
<Compile Include="UserManual\StandardHtmlUserManualFixture.cs" />
8990
</ItemGroup>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using System;
2+
using FluentAssertions;
3+
using GitCommands;
4+
using GitUI.UserControls.RevisionGrid;
5+
using GitUIPluginInterfaces;
6+
using NSubstitute;
7+
using NUnit.Framework;
8+
9+
namespace GitUITests.UserControls.RevisionGrid
10+
{
11+
[TestFixture]
12+
public class GitRefListsForRevisionTests
13+
{
14+
private GitRevision _revision;
15+
private IGitModule _module;
16+
private IGitRef[] _refs;
17+
18+
[SetUp]
19+
public void Setup()
20+
{
21+
_module = Substitute.For<IGitModule>();
22+
_module.LocalConfigFile.Returns(Substitute.For<IConfigFileSettings>());
23+
24+
_refs = new IGitRef[]
25+
{
26+
new GitRef(_module, ObjectId.Random(), $"{GitRefName.RefsTagsPrefix}tag1"),
27+
new GitRef(_module, ObjectId.Random(), $"{GitRefName.RefsHeadsPrefix}branch1"),
28+
new GitRef(_module, ObjectId.Random(), $"{GitRefName.RefsRemotesPrefix}branch1"),
29+
};
30+
_revision = new GitRevision(ObjectId.Random())
31+
{
32+
Refs = _refs
33+
};
34+
}
35+
36+
[Test]
37+
public void ctor_must_throw_if_revision_null()
38+
{
39+
((Action)(() => new GitRefListsForRevision(null))).Should().Throw<ArgumentNullException>();
40+
}
41+
42+
[Test]
43+
public void ctor_must_throw_if_revision_ref_null()
44+
{
45+
((Action)(() => new GitRefListsForRevision(new GitRevision(ObjectId.Random()) { Refs = null }))).Should().Throw<ArgumentNullException>();
46+
}
47+
48+
[Test]
49+
public void AllBranches_must_return_all_revision_branches()
50+
{
51+
var grl = new GitRefListsForRevision(_revision);
52+
grl.AllBranches.Count.Should().Be(2);
53+
}
54+
55+
[Test]
56+
public void AllTags_must_return_all_revision_tags()
57+
{
58+
var grl = new GitRefListsForRevision(_revision);
59+
grl.AllTags.Count.Should().Be(1);
60+
}
61+
62+
[Test]
63+
public void GetAllBranchNames_must_return_branches_names()
64+
{
65+
var grl = new GitRefListsForRevision(_revision);
66+
grl.GetAllBranchNames().Should().BeEquivalentTo("branch1", "branch1");
67+
}
68+
69+
[Test]
70+
public void GetAllTagNames_must_return_branches_names()
71+
{
72+
var grl = new GitRefListsForRevision(_revision);
73+
grl.GetAllTagNames().Should().BeEquivalentTo("tag1");
74+
}
75+
76+
[Test]
77+
public void GetDeletableRefs_must_return_branches_names()
78+
{
79+
var grl = new GitRefListsForRevision(_revision);
80+
grl.GetDeletableRefs("branch1").Should().BeEquivalentTo(_refs[2], _refs[0]);
81+
}
82+
83+
[Test]
84+
public void GetRenameableLocalBranches_must_return_branches_names()
85+
{
86+
var grl = new GitRefListsForRevision(_revision);
87+
grl.GetRenameableLocalBranches().Should().BeEquivalentTo(_refs[1]);
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)