Skip to content

Commit f05a6a0

Browse files
authored
Generate Documentation Auto-Insert (#76665)
* wip * wip * wip * wip * wip * wip * wip * remove some commented out code * still cleaning up * revert file * clean up + option * wip * dispose of disable of intellicode line completions * comments * comments * add quota exceeded checks * fix tests * revert file * remove unused optional params * last few fixes * feedback * fix tests * small fix * fix * feedback * feedback * removed per comments * remove unused usings * feedback * feedback * move stuff around with new EA structure in roslyn * wip * feedback * feedbacl * fix * feedback * feedback * feedback * revert * remove null check * clean up * fix * fix tests * last fixes * telemetry + fixes * last comments
1 parent 2212158 commit f05a6a0

25 files changed

+840
-33
lines changed

src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ internal sealed class DocumentationCommentCommandHandler(
2525
IUIThreadOperationExecutor uiThreadOperationExecutor,
2626
ITextUndoHistoryRegistry undoHistoryRegistry,
2727
IEditorOperationsFactoryService editorOperationsFactoryService,
28-
EditorOptionsService editorOptionsService)
29-
: AbstractDocumentationCommentCommandHandler(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, editorOptionsService)
28+
EditorOptionsService editorOptionsService,
29+
CopilotGenerateDocumentationCommentManager generateDocumentationCommentManager)
30+
: AbstractDocumentationCommentCommandHandler(uiThreadOperationExecutor, undoHistoryRegistry,
31+
editorOperationsFactoryService, editorOptionsService, generateDocumentationCommentManager)
3032
{
3133
protected override string ExteriorTriviaText => "///";
3234
}

src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Linq;
77
using System.Threading;
8+
using Microsoft.CodeAnalysis.DocumentationComments;
89
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
910
using Microsoft.CodeAnalysis.Options;
1011
using Microsoft.CodeAnalysis.Shared.Extensions;
@@ -31,12 +32,14 @@ internal abstract class AbstractDocumentationCommentCommandHandler :
3132
private readonly ITextUndoHistoryRegistry _undoHistoryRegistry;
3233
private readonly IEditorOperationsFactoryService _editorOperationsFactoryService;
3334
private readonly EditorOptionsService _editorOptionsService;
35+
private readonly CopilotGenerateDocumentationCommentManager _generateDocumentationCommentManager;
3436

3537
protected AbstractDocumentationCommentCommandHandler(
3638
IUIThreadOperationExecutor uiThreadOperationExecutor,
3739
ITextUndoHistoryRegistry undoHistoryRegistry,
3840
IEditorOperationsFactoryService editorOperationsFactoryService,
39-
EditorOptionsService editorOptionsService)
41+
EditorOptionsService editorOptionsService,
42+
CopilotGenerateDocumentationCommentManager generateDocumentationCommentManager)
4043
{
4144
Contract.ThrowIfNull(uiThreadOperationExecutor);
4245
Contract.ThrowIfNull(undoHistoryRegistry);
@@ -46,6 +49,7 @@ protected AbstractDocumentationCommentCommandHandler(
4649
_undoHistoryRegistry = undoHistoryRegistry;
4750
_editorOperationsFactoryService = editorOperationsFactoryService;
4851
_editorOptionsService = editorOptionsService;
52+
_generateDocumentationCommentManager = generateDocumentationCommentManager;
4953
}
5054

5155
protected abstract string ExteriorTriviaText { get; }
@@ -97,13 +101,17 @@ private bool CompleteComment(
97101
if (snippet != null)
98102
{
99103
ApplySnippet(snippet, subjectBuffer, textView);
104+
var oldSnapshot = subjectBuffer.CurrentSnapshot;
105+
var oldCaret = textView.Caret.Position.VirtualBufferPosition;
106+
100107
returnValue = true;
108+
109+
_generateDocumentationCommentManager.TriggerDocumentationCommentProposalGeneration(document, snippet, oldSnapshot, oldCaret, textView, cancellationToken);
101110
}
102111
}
103112

104113
return returnValue;
105114
}
106-
107115
public CommandState GetCommandState(TypeCharCommandArgs args, Func<CommandState> nextHandler)
108116
=> nextHandler();
109117

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.ComponentModel.Composition;
8+
using System.Linq;
9+
using System.Text;
10+
using System.Threading;
11+
using System.Threading.Tasks;
12+
using Microsoft.CodeAnalysis.Copilot;
13+
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
14+
using Microsoft.CodeAnalysis.Host.Mef;
15+
using Microsoft.CodeAnalysis.Shared.Extensions;
16+
using Microsoft.CodeAnalysis.Shared.TestHooks;
17+
using Microsoft.VisualStudio.Language.Suggestions;
18+
using Microsoft.VisualStudio.Text;
19+
using Microsoft.VisualStudio.Text.Editor;
20+
21+
namespace Microsoft.CodeAnalysis.DocumentationComments
22+
{
23+
[Export(typeof(CopilotGenerateDocumentationCommentManager))]
24+
internal class CopilotGenerateDocumentationCommentManager
25+
{
26+
private readonly SuggestionServiceBase? _suggestionServiceBase;
27+
private readonly IThreadingContext _threadingContext;
28+
private readonly IAsynchronousOperationListener _asyncListener;
29+
30+
[ImportingConstructor]
31+
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
32+
public CopilotGenerateDocumentationCommentManager([Import(AllowDefault = true)] SuggestionServiceBase? suggestionServiceBase, IThreadingContext threadingContext,
33+
IAsynchronousOperationListenerProvider listenerProvider)
34+
{
35+
_suggestionServiceBase = suggestionServiceBase;
36+
_threadingContext = threadingContext;
37+
_asyncListener = listenerProvider.GetListener(FeatureAttribute.GenerateDocumentation);
38+
}
39+
40+
public void TriggerDocumentationCommentProposalGeneration(Document document,
41+
DocumentationCommentSnippet snippet, ITextSnapshot snapshot, VirtualSnapshotPoint caret, ITextView textView, CancellationToken cancellationToken)
42+
{
43+
if (_suggestionServiceBase is null)
44+
{
45+
return;
46+
}
47+
48+
var token = _asyncListener.BeginAsyncOperation(nameof(GenerateDocumentationCommentProposalsAsync));
49+
_ = GenerateDocumentationCommentProposalsAsync(document, snippet, snapshot, caret, textView, cancellationToken).CompletesAsyncOperation(token);
50+
}
51+
52+
private async Task GenerateDocumentationCommentProposalsAsync(Document document, DocumentationCommentSnippet snippet, ITextSnapshot snapshot, VirtualSnapshotPoint caret, ITextView textView, CancellationToken cancellationToken)
53+
{
54+
var generateDocumentationCommentProvider = await CreateProviderAsync(document, textView, cancellationToken).ConfigureAwait(false);
55+
if (generateDocumentationCommentProvider is not null)
56+
{
57+
await generateDocumentationCommentProvider.GenerateDocumentationProposalAsync(snippet, snapshot, caret, cancellationToken).ConfigureAwait(false);
58+
}
59+
}
60+
61+
private async Task<CopilotGenerateDocumentationCommentProvider?> CreateProviderAsync(Document document, ITextView textView, CancellationToken cancellationToken)
62+
{
63+
var copilotService = await IsGenerateDocumentationAvailableAsync(document, cancellationToken).ConfigureAwait(false);
64+
65+
if (copilotService is null)
66+
{
67+
return null;
68+
}
69+
70+
var provider = textView.Properties.GetOrCreateSingletonProperty(typeof(CopilotGenerateDocumentationCommentProvider),
71+
() => new CopilotGenerateDocumentationCommentProvider(_threadingContext, copilotService));
72+
73+
await provider!.InitializeAsync(textView, _suggestionServiceBase!, cancellationToken).ConfigureAwait(false);
74+
75+
return provider;
76+
}
77+
78+
private static async Task<ICopilotCodeAnalysisService?> IsGenerateDocumentationAvailableAsync(Document document, CancellationToken cancellationToken)
79+
{
80+
// Bailing out if copilot is not available or the option is not enabled.
81+
if (document.GetLanguageService<ICopilotOptionsService>() is not { } copilotOptionService ||
82+
!await copilotOptionService.IsGenerateDocumentationCommentOptionEnabledAsync().ConfigureAwait(false))
83+
{
84+
return null;
85+
}
86+
87+
if (document.GetLanguageService<ICopilotCodeAnalysisService>() is not { } copilotService ||
88+
await copilotService.IsAvailableAsync(cancellationToken).ConfigureAwait(false) is false)
89+
{
90+
return null;
91+
}
92+
93+
return copilotService;
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)