5
5
using System . Linq ;
6
6
using System . Reactive . Linq ;
7
7
using System . Threading . Tasks ;
8
+ using EnvDTE ;
8
9
using GitHub . Commands ;
9
10
using GitHub . Extensions ;
10
11
using GitHub . Models ;
12
+ using GitHub . Models . Drafts ;
13
+ using GitHub . ViewModels ;
11
14
using GitHub . VisualStudio ;
12
15
using Microsoft . VisualStudio ;
13
16
using Microsoft . VisualStudio . Editor ;
18
21
using Microsoft . VisualStudio . Text . Editor ;
19
22
using Microsoft . VisualStudio . Text . Projection ;
20
23
using Microsoft . VisualStudio . TextManager . Interop ;
21
- using EnvDTE ;
22
24
using Task = System . Threading . Tasks . Task ;
23
25
24
26
namespace GitHub . Services
@@ -39,6 +41,8 @@ public class PullRequestEditorService : IPullRequestEditorService
39
41
readonly IStatusBarNotificationService statusBar ;
40
42
readonly IGoToSolutionOrPullRequestFileCommand goToSolutionOrPullRequestFileCommand ;
41
43
readonly IEditorOptionsFactoryService editorOptionsFactoryService ;
44
+ readonly IMessageDraftStore draftStore ;
45
+ readonly IInlineCommentPeekService peekService ;
42
46
readonly IUsageTracker usageTracker ;
43
47
44
48
[ ImportingConstructor ]
@@ -49,6 +53,8 @@ public PullRequestEditorService(
49
53
IStatusBarNotificationService statusBar ,
50
54
IGoToSolutionOrPullRequestFileCommand goToSolutionOrPullRequestFileCommand ,
51
55
IEditorOptionsFactoryService editorOptionsFactoryService ,
56
+ IMessageDraftStore draftStore ,
57
+ IInlineCommentPeekService peekService ,
52
58
IUsageTracker usageTracker )
53
59
{
54
60
Guard . ArgumentNotNull ( serviceProvider , nameof ( serviceProvider ) ) ;
@@ -58,13 +64,17 @@ public PullRequestEditorService(
58
64
Guard . ArgumentNotNull ( goToSolutionOrPullRequestFileCommand , nameof ( goToSolutionOrPullRequestFileCommand ) ) ;
59
65
Guard . ArgumentNotNull ( goToSolutionOrPullRequestFileCommand , nameof ( editorOptionsFactoryService ) ) ;
60
66
Guard . ArgumentNotNull ( usageTracker , nameof ( usageTracker ) ) ;
67
+ Guard . ArgumentNotNull ( peekService , nameof ( peekService ) ) ;
68
+ Guard . ArgumentNotNull ( draftStore , nameof ( draftStore ) ) ;
61
69
62
70
this . serviceProvider = serviceProvider ;
63
71
this . pullRequestService = pullRequestService ;
64
72
this . vsEditorAdaptersFactory = vsEditorAdaptersFactory ;
65
73
this . statusBar = statusBar ;
66
74
this . goToSolutionOrPullRequestFileCommand = goToSolutionOrPullRequestFileCommand ;
67
75
this . editorOptionsFactoryService = editorOptionsFactoryService ;
76
+ this . draftStore = draftStore ;
77
+ this . peekService = peekService ;
68
78
this . usageTracker = usageTracker ;
69
79
}
70
80
@@ -129,7 +139,7 @@ public async Task<ITextView> OpenFile(
129
139
}
130
140
131
141
/// <inheritdoc/>
132
- public async Task < IDifferenceViewer > OpenDiff ( IPullRequestSession session , string relativePath , string headSha , bool scrollToFirstDiff )
142
+ public async Task < IDifferenceViewer > OpenDiff ( IPullRequestSession session , string relativePath , string headSha , bool scrollToFirstDraftOrDiff )
133
143
{
134
144
Guard . ArgumentNotNull ( session , nameof ( session ) ) ;
135
145
Guard . ArgumentNotEmptyString ( relativePath , nameof ( relativePath ) ) ;
@@ -168,12 +178,37 @@ await pullRequestService.ExtractToTempFile(
168
178
var caption = $ "Diff - { Path . GetFileName ( file . RelativePath ) } ";
169
179
var options = __VSDIFFSERVICEOPTIONS . VSDIFFOPT_DetectBinaryFiles |
170
180
__VSDIFFSERVICEOPTIONS . VSDIFFOPT_LeftFileIsTemporary ;
181
+ var openThread = ( line : - 1 , side : DiffSide . Left ) ;
182
+ var scrollToFirstDiff = false ;
171
183
172
184
if ( ! workingDirectory )
173
185
{
174
186
options |= __VSDIFFSERVICEOPTIONS . VSDIFFOPT_RightFileIsTemporary ;
175
187
}
176
188
189
+ if ( scrollToFirstDraftOrDiff )
190
+ {
191
+ var ( key , _) = PullRequestReviewCommentThreadViewModel . GetDraftKeys (
192
+ session . LocalRepository . CloneUrl . WithOwner ( session . RepositoryOwner ) ,
193
+ session . PullRequest . Number ,
194
+ relativePath ,
195
+ 0 ) ;
196
+ var drafts = ( await draftStore . GetDrafts < PullRequestReviewCommentDraft > ( key )
197
+ . ConfigureAwait ( true ) )
198
+ . OrderByDescending ( x => x . data . UpdatedAt )
199
+ . ToList ( ) ;
200
+
201
+ if ( drafts . Count > 0 && int . TryParse ( drafts [ 0 ] . secondaryKey , out var line ) )
202
+ {
203
+ openThread = ( line , drafts [ 0 ] . data . Side ) ;
204
+ scrollToFirstDiff = false ;
205
+ }
206
+ else
207
+ {
208
+ scrollToFirstDiff = true ;
209
+ }
210
+ }
211
+
177
212
IVsWindowFrame frame ;
178
213
using ( OpenWithOption ( DifferenceViewerOptions . ScrollToFirstDiffName , scrollToFirstDiff ) )
179
214
using ( OpenInProvisionalTab ( ) )
@@ -228,6 +263,18 @@ await pullRequestService.ExtractToTempFile(
228
263
else
229
264
await usageTracker . IncrementCounter ( x => x . NumberOfPRDetailsViewChanges ) ;
230
265
266
+ if ( openThread . line != - 1 )
267
+ {
268
+ var view = diffViewer . ViewMode == DifferenceViewMode . Inline ?
269
+ diffViewer . InlineView :
270
+ openThread . side == DiffSide . Left ? diffViewer . LeftView : diffViewer . RightView ;
271
+
272
+ // HACK: We need to wait here for the view to initialize or the peek session won't appear.
273
+ // There must be a better way of doing this.
274
+ await Task . Delay ( 1500 ) . ConfigureAwait ( true ) ;
275
+ peekService . Show ( view , openThread . side , openThread . line ) ;
276
+ }
277
+
231
278
return diffViewer ;
232
279
}
233
280
catch ( Exception e )
@@ -247,7 +294,7 @@ public async Task<IDifferenceViewer> OpenDiff(
247
294
Guard . ArgumentNotEmptyString ( relativePath , nameof ( relativePath ) ) ;
248
295
Guard . ArgumentNotNull ( thread , nameof ( thread ) ) ;
249
296
250
- var diffViewer = await OpenDiff ( session , relativePath , thread . CommitSha , scrollToFirstDiff : false ) ;
297
+ var diffViewer = await OpenDiff ( session , relativePath , thread . CommitSha , scrollToFirstDraftOrDiff : false ) ;
251
298
252
299
var param = ( object ) new InlineCommentNavigationParams
253
300
{
0 commit comments