Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit ce8cb5b

Browse files
committed
Merge branch 'master' into fixes/1444-pr-session-manager-tests-factory
2 parents 40d66be + 0405986 commit ce8cb5b

34 files changed

+655
-69
lines changed

appveyor.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: '2.4.0.{build}'
1+
version: '2.4.2.{build}'
22
skip_tags: true
33
install:
44
- ps: |
@@ -19,8 +19,10 @@ install:
1919
nuget restore GitHubVS.sln
2020
build_script:
2121
- ps: scripts\build.ps1 -AppVeyor -BuildNumber:$env:APPVEYOR_BUILD_NUMBER
22-
test_script:
23-
- ps: scripts\test.ps1 -AppVeyor
22+
test:
23+
categories:
24+
except:
25+
- Timings
2426
on_success:
2527
- ps: |
2628
if ($full_build) {
-7.67 KB
Binary file not shown.

scripts/test.ps1

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ Param(
1818
$TimeoutDuration = 180
1919
,
2020
[switch]
21-
$AppVeyor = $false
22-
,
23-
[switch]
2421
$Trace = $false
2522

2623
)
@@ -35,30 +32,30 @@ $env:PATH = "$PSScriptRoot;$env:PATH"
3532
$exitcode = 0
3633

3734
Write-Output "Running Tracking Collection Tests..."
38-
Run-NUnit test TrackingCollectionTests $TimeoutDuration $config -AppVeyor:$AppVeyor
35+
Run-NUnit test TrackingCollectionTests $TimeoutDuration $config
3936
if (!$?) {
4037
$exitcode = 1
4138
}
4239

4340
Write-Output "Running GitHub.UI.UnitTests..."
44-
Run-NUnit test GitHub.UI.UnitTests $TimeoutDuration $config -AppVeyor:$AppVeyor
41+
Run-NUnit test GitHub.UI.UnitTests $TimeoutDuration $config
4542
if (!$?) {
4643
$exitcode = 2
4744
}
4845

4946
Write-Output "Running UnitTests..."
50-
Run-NUnit test UnitTests $TimeoutDuration $config -AppVeyor:$AppVeyor
47+
Run-NUnit test UnitTests $TimeoutDuration $config
5148
if (!$?) {
5249
$exitcode = 3
5350
}
5451

5552
Write-Output "Running GitHub.InlineReviews.UnitTests..."
56-
Run-NUnit test GitHub.InlineReviews.UnitTests $TimeoutDuration $config -AppVeyor:$AppVeyor
53+
Run-NUnit test GitHub.InlineReviews.UnitTests $TimeoutDuration $config
5754
if (!$?) {
5855
$exitcode = 4
5956
}
6057

61-
if ($exitcode -ne 0 -and $AppVeyor) {
58+
if ($exitcode -ne 0) {
6259
$host.SetShouldExit($exitcode)
6360
}
6461
exit $exitcode

src/GitHub.App/GitHub.App.csproj

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@
6161
<HintPath>..\..\packages\Microsoft.VisualStudio.ComponentModelHost.14.0.25424\lib\net45\Microsoft.VisualStudio.ComponentModelHost.dll</HintPath>
6262
<Private>True</Private>
6363
</Reference>
64+
<Reference Include="Microsoft.VisualStudio.OLE.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
65+
<HintPath>..\..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6070\lib\Microsoft.VisualStudio.OLE.Interop.dll</HintPath>
66+
<Private>True</Private>
67+
</Reference>
6468
<Reference Include="Microsoft.VisualStudio.Shell.14.0, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
6569
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.14.0.14.3.25407\lib\Microsoft.VisualStudio.Shell.14.0.dll</HintPath>
6670
<Private>True</Private>
@@ -69,10 +73,18 @@
6973
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.10.0.30319\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll</HintPath>
7074
<Private>True</Private>
7175
</Reference>
76+
<Reference Include="Microsoft.VisualStudio.Shell.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
77+
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6071\lib\Microsoft.VisualStudio.Shell.Interop.dll</HintPath>
78+
<Private>True</Private>
79+
</Reference>
7280
<Reference Include="Microsoft.VisualStudio.TextManager.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
7381
<HintPath>..\..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6070\lib\Microsoft.VisualStudio.TextManager.Interop.dll</HintPath>
7482
<Private>True</Private>
7583
</Reference>
84+
<Reference Include="Microsoft.VisualStudio.TextManager.Interop.8.0, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
85+
<HintPath>..\..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.TextManager.Interop.8.0.dll</HintPath>
86+
<Private>True</Private>
87+
</Reference>
7688
<Reference Include="Microsoft.VisualStudio.Threading, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
7789
<SpecificVersion>False</SpecificVersion>
7890
<HintPath>..\..\packages\Microsoft.VisualStudio.Threading.14.1.131\lib\net45\Microsoft.VisualStudio.Threading.dll</HintPath>
@@ -142,6 +154,7 @@
142154
<Compile Include="Models\PullRequestDetailArgument.cs" />
143155
<Compile Include="Services\EnterpriseCapabilitiesService.cs" />
144156
<Compile Include="Services\GlobalConnection.cs" />
157+
<Compile Include="Services\PullRequestEditorService.cs" />
145158
<Compile Include="Services\TeamExplorerContext.cs" />
146159
<Compile Include="Services\OAuthCallbackListener.cs" />
147160
<Compile Include="ViewModels\Dialog\GistCreationViewModel.cs" />
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
using System.Collections.Generic;
2+
using System.ComponentModel.Composition;
3+
using Microsoft.VisualStudio;
4+
using Microsoft.VisualStudio.Shell;
5+
using Microsoft.VisualStudio.Shell.Interop;
6+
using Microsoft.VisualStudio.TextManager.Interop;
7+
using GitHub.Models;
8+
9+
namespace GitHub.Services
10+
{
11+
[Export(typeof(IPullRequestEditorService))]
12+
public class PullRequestEditorService : IPullRequestEditorService
13+
{
14+
readonly IGitHubServiceProvider serviceProvider;
15+
16+
// If the target line doesn't have a unique match, search this number of lines above looking for a match.
17+
public const int MatchLinesAboveTarget = 4;
18+
19+
[ImportingConstructor]
20+
public PullRequestEditorService(IGitHubServiceProvider serviceProvider)
21+
{
22+
this.serviceProvider = serviceProvider;
23+
}
24+
25+
public IVsTextView NavigateToEquivalentPosition(IVsTextView sourceView, string targetFile)
26+
{
27+
int line;
28+
int column;
29+
ErrorHandler.ThrowOnFailure(sourceView.GetCaretPos(out line, out column));
30+
var text1 = GetText(sourceView);
31+
32+
var view = OpenDocument(targetFile);
33+
var text2 = VsShellUtilities.GetRunningDocumentContents(serviceProvider, targetFile);
34+
35+
var fromLines = ReadLines(text1);
36+
var toLines = ReadLines(text2);
37+
var matchingLine = FindMatchingLine(fromLines, toLines, line, matchLinesAbove: MatchLinesAboveTarget);
38+
if (matchingLine == -1)
39+
{
40+
// If we can't match line use orignal as best guess.
41+
matchingLine = line < toLines.Count ? line : toLines.Count - 1;
42+
column = 0;
43+
}
44+
45+
ErrorHandler.ThrowOnFailure(view.SetCaretPos(matchingLine, column));
46+
ErrorHandler.ThrowOnFailure(view.CenterLines(matchingLine, 1));
47+
48+
return view;
49+
}
50+
51+
public IVsTextView FindActiveView()
52+
{
53+
var textManager = serviceProvider.GetService<SVsTextManager, IVsTextManager2>();
54+
IVsTextView view;
55+
var hresult = textManager.GetActiveView2(1, null, (uint)_VIEWFRAMETYPE.vftCodeWindow, out view);
56+
return hresult == VSConstants.S_OK ? view : null;
57+
}
58+
59+
/// <summary>
60+
/// Find the closest matching line in <see cref="toLines"/>.
61+
/// </summary>
62+
/// <remarks>
63+
/// When matching we prioritize unique matching lines in <see cref="toLines"/>. If the target line isn't
64+
/// unique, continue searching the lines above for a better match and use this as anchor with an offset.
65+
/// The closest match to <see cref="line"/> with the fewest duplicate matches will be used for the matching line.
66+
/// </remarks>
67+
/// <param name="fromLines">The document we're navigating from.</param>
68+
/// <param name="toLines">The document we're navigating to.</param>
69+
/// <param name="line">The 0-based line we're navigating from.</param>
70+
/// <returns>The best matching line in <see cref="toLines"/></returns>
71+
public int FindMatchingLine(IList<string> fromLines, IList<string> toLines, int line, int matchLinesAbove = 0)
72+
{
73+
var matchingLine = -1;
74+
var minMatchedLines = -1;
75+
for (var offset = 0; offset <= matchLinesAbove; offset++)
76+
{
77+
var targetLine = line - offset;
78+
if (targetLine < 0)
79+
{
80+
break;
81+
}
82+
83+
int matchedLines;
84+
var nearestLine = FindNearestMatchingLine(fromLines, toLines, targetLine, out matchedLines);
85+
if (nearestLine != -1)
86+
{
87+
if (matchingLine == -1 || minMatchedLines >= matchedLines)
88+
{
89+
matchingLine = nearestLine + offset;
90+
minMatchedLines = matchedLines;
91+
}
92+
93+
if (minMatchedLines == 1)
94+
{
95+
break; // We've found a unique matching line!
96+
}
97+
}
98+
}
99+
100+
if (matchingLine >= toLines.Count)
101+
{
102+
matchingLine = toLines.Count - 1;
103+
}
104+
105+
return matchingLine;
106+
}
107+
108+
/// <summary>
109+
/// Find the nearest matching line to <see cref="line"/> and the number of similar matched lines in the text.
110+
/// </summary>
111+
/// <param name="fromLines">The document we're navigating from.</param>
112+
/// <param name="toLines">The document we're navigating to.</param>
113+
/// <param name="line">The 0-based line we're navigating from.</param>
114+
/// <param name="matchedLines">The number of similar matched lines in <see cref="toLines"/></param>
115+
/// <returns>Find the nearest matching line in <see cref="toLines"/>.</returns>
116+
public int FindNearestMatchingLine(IList<string> fromLines, IList<string> toLines, int line, out int matchedLines)
117+
{
118+
line = line < fromLines.Count ? line : fromLines.Count - 1; // VS shows one extra line at end
119+
var fromLine = fromLines[line];
120+
121+
matchedLines = 0;
122+
var matchingLine = -1;
123+
for (var offset = 0; true; offset++)
124+
{
125+
var lineAbove = line + offset;
126+
var checkAbove = lineAbove < toLines.Count;
127+
if (checkAbove && toLines[lineAbove] == fromLine)
128+
{
129+
if (matchedLines == 0)
130+
{
131+
matchingLine = lineAbove;
132+
}
133+
134+
matchedLines++;
135+
}
136+
137+
var lineBelow = line - offset;
138+
var checkBelow = lineBelow >= 0;
139+
if (checkBelow && offset > 0 && lineBelow < toLines.Count && toLines[lineBelow] == fromLine)
140+
{
141+
if (matchedLines == 0)
142+
{
143+
matchingLine = lineBelow;
144+
}
145+
146+
matchedLines++;
147+
}
148+
149+
if (!checkAbove && !checkBelow)
150+
{
151+
break;
152+
}
153+
}
154+
155+
return matchingLine;
156+
}
157+
158+
string GetText(IVsTextView textView)
159+
{
160+
IVsTextLines buffer;
161+
ErrorHandler.ThrowOnFailure(textView.GetBuffer(out buffer));
162+
163+
int line;
164+
int index;
165+
ErrorHandler.ThrowOnFailure(buffer.GetLastLineIndex(out line, out index));
166+
167+
string text;
168+
ErrorHandler.ThrowOnFailure(buffer.GetLineText(0, 0, line, index, out text));
169+
return text;
170+
}
171+
172+
IVsTextView OpenDocument(string fullPath)
173+
{
174+
var logicalView = VSConstants.LOGVIEWID.TextView_guid;
175+
IVsUIHierarchy hierarchy;
176+
uint itemID;
177+
IVsWindowFrame windowFrame;
178+
IVsTextView view;
179+
VsShellUtilities.OpenDocument(serviceProvider, fullPath, logicalView, out hierarchy, out itemID, out windowFrame, out view);
180+
return view;
181+
}
182+
183+
static IList<string> ReadLines(string text)
184+
{
185+
var lines = new List<string>();
186+
var reader = new DiffUtilities.LineReader(text);
187+
string line;
188+
while ((line = reader.ReadLine()) != null)
189+
{
190+
lines.Add(line);
191+
}
192+
193+
return lines;
194+
}
195+
}
196+
}

src/GitHub.App/ViewModels/GitHubPane/GitHubPaneViewModel.cs

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ public sealed class GitHubPaneViewModel : ViewModelBase, IGitHubPaneViewModel, I
4646
readonly ReactiveCommand<Unit> refresh;
4747
readonly ReactiveCommand<Unit> showPullRequests;
4848
readonly ReactiveCommand<object> openInBrowser;
49+
readonly SemaphoreSlim initializing = new SemaphoreSlim(1);
50+
bool initialized;
4951
IViewModel content;
5052
ILocalRepositoryModel localRepository;
5153
string searchQuery;
@@ -198,26 +200,37 @@ public void Dispose()
198200
/// <inheritdoc/>
199201
public async Task InitializeAsync(IServiceProvider paneServiceProvider)
200202
{
201-
await UpdateContent(teamExplorerContext.ActiveRepository);
202-
teamExplorerContext.WhenAnyValue(x => x.ActiveRepository)
203-
.Skip(1)
204-
.ObserveOn(RxApp.MainThreadScheduler)
205-
.Subscribe(x => UpdateContent(x).Forget());
206-
207-
connectionManager.Connections.CollectionChanged += (_, __) => UpdateContent(LocalRepository).Forget();
208-
209-
BindNavigatorCommand(paneServiceProvider, PkgCmdIDList.pullRequestCommand, showPullRequests);
210-
BindNavigatorCommand(paneServiceProvider, PkgCmdIDList.backCommand, navigator.NavigateBack);
211-
BindNavigatorCommand(paneServiceProvider, PkgCmdIDList.forwardCommand, navigator.NavigateForward);
212-
BindNavigatorCommand(paneServiceProvider, PkgCmdIDList.refreshCommand, refresh);
213-
BindNavigatorCommand(paneServiceProvider, PkgCmdIDList.githubCommand, openInBrowser);
214-
215-
paneServiceProvider.AddCommandHandler(Guids.guidGitHubToolbarCmdSet, PkgCmdIDList.helpCommand,
216-
(_, __) =>
217-
{
218-
browser.OpenUrl(new Uri(GitHubUrls.Documentation));
219-
usageTracker.IncrementCounter(x => x.NumberOfGitHubPaneHelpClicks).Forget();
220-
});
203+
await initializing.WaitAsync();
204+
if (initialized) return;
205+
206+
try
207+
{
208+
await UpdateContent(teamExplorerContext.ActiveRepository);
209+
teamExplorerContext.WhenAnyValue(x => x.ActiveRepository)
210+
.Skip(1)
211+
.ObserveOn(RxApp.MainThreadScheduler)
212+
.Subscribe(x => UpdateContent(x).Forget());
213+
214+
connectionManager.Connections.CollectionChanged += (_, __) => UpdateContent(LocalRepository).Forget();
215+
216+
BindNavigatorCommand(paneServiceProvider, PkgCmdIDList.pullRequestCommand, showPullRequests);
217+
BindNavigatorCommand(paneServiceProvider, PkgCmdIDList.backCommand, navigator.NavigateBack);
218+
BindNavigatorCommand(paneServiceProvider, PkgCmdIDList.forwardCommand, navigator.NavigateForward);
219+
BindNavigatorCommand(paneServiceProvider, PkgCmdIDList.refreshCommand, refresh);
220+
BindNavigatorCommand(paneServiceProvider, PkgCmdIDList.githubCommand, openInBrowser);
221+
222+
paneServiceProvider.AddCommandHandler(Guids.guidGitHubToolbarCmdSet, PkgCmdIDList.helpCommand,
223+
(_, __) =>
224+
{
225+
browser.OpenUrl(new Uri(GitHubUrls.Documentation));
226+
usageTracker.IncrementCounter(x => x.NumberOfGitHubPaneHelpClicks).Forget();
227+
});
228+
}
229+
finally
230+
{
231+
initialized = true;
232+
initializing.Release();
233+
}
221234
}
222235

223236
/// <inheritdoc/>

src/GitHub.App/packages.config

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
<package id="LibGit2Sharp" version="0.23.1" targetFramework="net461" />
44
<package id="LibGit2Sharp.NativeBinaries" version="1.0.164" targetFramework="net461" />
55
<package id="Microsoft.VisualStudio.ComponentModelHost" version="14.0.25424" targetFramework="net461" />
6+
<package id="Microsoft.VisualStudio.OLE.Interop" version="7.10.6070" targetFramework="net461" />
67
<package id="Microsoft.VisualStudio.Shell.14.0" version="14.3.25407" targetFramework="net461" />
78
<package id="Microsoft.VisualStudio.Shell.Immutable.10.0" version="10.0.30319" targetFramework="net461" />
9+
<package id="Microsoft.VisualStudio.Shell.Interop" version="7.10.6071" targetFramework="net461" />
810
<package id="Microsoft.VisualStudio.TextManager.Interop" version="7.10.6070" targetFramework="net461" />
11+
<package id="Microsoft.VisualStudio.TextManager.Interop.8.0" version="8.0.50727" targetFramework="net461" />
912
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net45" />
1013
<package id="Rothko" version="0.0.3-ghfvs" targetFramework="net461" />
1114
<package id="Rx-Core" version="2.2.5-custom" targetFramework="net45" />

0 commit comments

Comments
 (0)