-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for copilot-generated summaries in quick info. (On-the-fly docs) #12552
base: main
Are you sure you want to change the base?
Conversation
…hen editor isnt selected
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a few wording comments but mostly looks good to me ✨. Leaving official sign-off for cpptools owners.
); | ||
} catch (err) { | ||
if (err instanceof vscode.LanguageModelError) { | ||
console.log(err.message, err.code, err.cause); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what standard practice is in cpptools, but should we be sending some error telemetry here too?
@spebl Did you want this in our next 1.22.x or what release? |
Not currently targeting a specific release, no need to block anything on this going in. I first wanted to get feedback on this approach, along with the upgrading of the vscode version. I'm taking a look now at how we can best keep support for the older versions while also using the new language model apis when available. |
…s and cleanup based on feedback. add waiting spinner.
// This uses several workarounds for interacting with the hover feature. | ||
// A proposal for dynamic hover content would help, such as the one here (https://github.com/microsoft/vscode/issues/195394) | ||
async function onCopilotHover(): Promise<void> { | ||
if (!vscode.window.activeTextEditor) { return; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does our linter allow this? I expected that it would want:
if (!vscode.window.activeTextEditor) {
return;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bobbrow Our formatter recently changed and allows this currently. Maybe there's some setting we need to change to alter it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can look into it later. I'm not a fan of this style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant to update this to match the rest of the formatting, I'll update it now. I don't have any strong preference for one or the other.
@@ -1536,7 +1556,7 @@ export class DefaultClient implements Client { | |||
resetDatabase: resetDatabase, | |||
edgeMessagesDirectory: path.join(util.getExtensionFilePath("bin"), "messages", getLocaleId()), | |||
localizedStrings: localizedStrings, | |||
settings: this.getAllSettings() | |||
settings: await this.getAllSettings() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm almost certain we avoided asyncs early in client creation code, as a fix for issues that occurs due to race conditions at startup. I don't recall the exact details at the moment. But the call to createLanguageClient
is not awaited (it's called from a constructor, and constructors aren't async). So, with your change, it's possible for the client to get constructed and presumably calls to this.languageClient
to occur before that variable is properly set. I think that's why there are no awaits there until after languageClient
is set and everything has been hooked up.
Would it be possible to remove this async/await and deliver the setting value without awaiting to see if the flight is enabled? Then, gate the functionality later based on whether the flight is enabled?
@@ -89,7 +89,17 @@ export function createProtocolFilter(): Middleware { | |||
provideHover: async (document, position, token, next: (document: any, position: any, token: any) => any) => clients.ActiveClient.enqueue(async () => { | |||
const me: Client = clients.getClientFor(document.uri); | |||
if (me.TrackedDocuments.has(document.uri.toString())) { | |||
return next(document, position, token); | |||
// Currently needed to support icons. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes me nervous. It looks like you're potentially hijacking any hover response, if it happens to contain an array that has a markdown string in it.
I think it would be cleaner if we switched to using a HoverProvider
instead of hacking around the LSP hover request. (Then you'd be more easily able to do pre/post processing of the request in TypeScript code. That may also help avoid that async/await to check if the flight is enabled, as that could happen in the a HoverProvider
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I think having a hover provider would allow everything to be done in the same hover request, without needing to add additional custom LSP messages. Instead, you could add additional fields to a primary hover request message, and do any additional work immediately before or after forwarding that to the native process using sendRequest
, like the other provider classes.
public async showCopilotHover(content: string): Promise<ShowCopilotHoverResult> { | ||
const params: ShowCopilotHoverParams = {content: content}; | ||
await this.ready; | ||
return this.languageClient.sendRequest(ShowCopilotHoverRequest, params); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's common for multiple hover requests to be issued and get backlogged as the user moves the mouse around. As each one is generated, the prior one is cancelled. I think the cancellation token needs to be plumbed up here, all the way to these calls to sendRequest
, in order for the lsp_manager
on the native side to handle cancellation.
Cancellation will now cause an exception to be thrown from sendRequest
, which you could catch, check for the specific cancellation error code, and handle appropriately (i.e., to throw a CancellationError exception, if that is what calling code expects).
Capturing notes from a quick discussion I had with @Colengms. He's going to go ahead and move from LSP-based hover to a |
@@ -3286,6 +3286,17 @@ | |||
"default": false, | |||
"markdownDescription": "%c_cpp.configuration.addNodeAddonIncludePaths.markdownDescription%", | |||
"scope": "application" | |||
}, | |||
"C_Cpp.copilotHover": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
await vscode.window.showTextDocument(vscode.window.activeTextEditor.document, { preserveFocus: false, selection: new vscode.Selection(hoverPosition, hoverPosition) }); | ||
|
||
// Same workaround as above to force the editor to update it's content. | ||
await clients.ActiveClient.showCopilotHover('$(loading~spin)'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have a way to do this other than wiggling the mouse.
VS Code generally merges results from multiple providers. I suspect if there are multiple HoverProviders and only one returns results (yet) it will show only one result. If that result had the link in it, and that link 'unblocked' a secondary HoverProvider from returning an AI result, I suspect VS Code would then populate a new 'section' of the tooltip with the additional provider result. That is just a guess, I haven't tried it. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I finally got a chance to try this out, and it almost works perfectly, but unfortunately while the provider is blocking waiting for the signal, VS Code reserves hover space for it and displays "Loading..." until it's finally unblocked and the Promise resolves.
If you have any ideas on a way to not show the "Loading..." message, I think everything else should work. So far everything I've tried has hit either that same issue or the issue of the Hover content not updating after being rendered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could put in a request to VS Code, to make this more perfect? :) Since this is AI related, they might consider it a priority. Hypothetically, if there were N hover providers, does it make sense for VS Code to show N Loading...
messages? Seems like just one would suffice, and additional results could appear for additional providers, once they provide results. That might be easy for them to fix. I'd suggest opening an issue against VS Code and seeing what they think. https://github.com/microsoft/vscode/issues
await vscode.commands.executeCommand('editor.action.showHover', { focus: 'noAutoFocus' }); | ||
|
||
// Move back and show the correct hover. | ||
await clients.ActiveClient.showCopilotHover('$(loading~spin)'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The active document and active client could change after returning from an await. I think this could be leading to bugs I'm seeing when switching between documents and hovering.
// This uses several workarounds for interacting with the hover feature. | ||
// A proposal for dynamic hover content would help, such as the one here (https://github.com/microsoft/vscode/issues/195394) | ||
async function onCopilotHover(): Promise<void> { | ||
if (!vscode.window.activeTextEditor) { return; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hover is supposed to work on a document that is not the active editor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the hover disappear when Generate Copilot summary is clicked and there is no summary result.
|
||
// Workaround to force the editor to update it's content, needs to be called from another location first. | ||
await vscode.commands.executeCommand('cursorMove', { to: 'right' }); | ||
await vscode.commands.executeCommand('editor.action.showHover', { focus: 'noAutoFocus' }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the user changes the document and cursor, it can trigger a different hover provider -- I got GitLens hover to be invoked and the line changed to some random line. It seems like it should save the original document or something.
const hoverPosition = new vscode.Position(copilotHoverResult.hoverPos.line, copilotHoverResult.hoverPos.character); | ||
|
||
// Make sure the editor has focus. | ||
await vscode.window.showTextDocument(vscode.window.activeTextEditor.document, { preserveFocus: false, selection: new vscode.Selection(hoverPosition, hoverPosition) }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the user switches active documents, it'll move the selection to an incorrect line (i.e. the line number of the previously active document), so they'll be at some random spot in the code which may not even have C++ hover, which is why I was getting only hover from GitLens in my other comment because it moved my cursor to hover over a space that had a GitLens inlay hint on it.
This introduces a new setting
C_Cpp.onTheFlyDocsEnabled
to control the display of the option to show copilot-generated summaries in the hover tooltip.When
enabled
, and also authenticated with the vscode-copilot extension, the hover tooltip will display an option to generate a summary of the symbol with copilot.The setting is defaulted to
default
which will check the feature flag control to determine if the feature should be enabled, which allows for slow rollout and the ability to rollback should any issues arise.Updating the vscode requirement to
1.90.0
to support using copilot features with "vscode.lm".The IntelliSense client changes supporting this feature are included in a separate PR against that repository.
Some workarounds were needed to support icon rendering in hover markdown and updating hover content dynamically which currently requires the hover to be closed and reopened. Potential fixes from proposals and unreleased patches are linked where applicable.
All feedback is very welcome!