diff --git a/package.json b/package.json index fd45f3c456..22fe669a80 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "workspace" ], "defaults": { - "roslyn": "5.0.0-1.25204.1", + "roslyn": "5.0.0-1.25214.2", "omniSharp": "1.39.12", "razor": "10.0.0-preview.25210.3", "razorOmnisharp": "7.0.0-preview.23363.1", diff --git a/src/lsptoolshost/copilot/contextProviders.ts b/src/lsptoolshost/copilot/contextProviders.ts index d9394d283d..403576ec0c 100644 --- a/src/lsptoolshost/copilot/contextProviders.ts +++ b/src/lsptoolshost/copilot/contextProviders.ts @@ -15,6 +15,8 @@ export const copilotLanguageServerExtensionComponentName = '@microsoft/visualstu export const copilotLanguageServerExtensionAssemblyName = 'Microsoft.VisualStudio.Copilot.Roslyn.LanguageServer.dll'; const copilotLanguageServerExtensionCapabilitiesFileName = 'capabilities.json'; +type ActiveExperiments = { [name: string]: string | number | boolean | string[] }; + export interface DocumentContext { textDocument: lsp.TextDocumentIdentifier; position: lsp.Position; @@ -25,12 +27,19 @@ export interface ContextResolveParam { completionId: string; timeBudget: number; data?: any; + activeExperiments: ActiveExperiments; } -const resolveContextMethodName = 'roslyn/resolveContext'; -const resolveContextMethodSupportedVersion = '1'; -const resolveContextRequest = new lsp.RequestType( - resolveContextMethodName, +const oldResolveContextMethodName = 'roslyn/resolveContext'; +const oldresolveContextMethodSupportedVersion = '1'; +const newResolveContextMethodName = 'roslyn/resolveContext@2'; +const newResolveContextMethodSupportedVersion = '1'; +const oldResolveContextRequest = new lsp.RequestType( + oldResolveContextMethodName, + lsp.ParameterStructures.auto +); +const newResolveContextRequest = new lsp.RequestType( + newResolveContextMethodName, lsp.ParameterStructures.auto ); @@ -60,6 +69,8 @@ function createContextResolveParam(request: ResolveRequest): ContextResolveParam }, completionId: request.completionId, timeBudget: request.timeBudget, + data: request.data, + activeExperiments: Object.fromEntries(request.activeExperiments), }; return contextResolveParam; } @@ -77,7 +88,8 @@ export function registerCopilotContextProviders( devkit.activate().then(async (devKitExports) => { try { // Check if the Copilot Language Server extension is installed and has the correct capabilities - let hasCapabilities = false; + // 0 means not support, 1 means old version, 2 means new version + let hasCapabilities = 0; const copilotServerExtensionfolder = devKitExports.components[copilotLanguageServerExtensionComponentName]; if (copilotServerExtensionfolder) { const capabilitiesFilePath = path.join( @@ -85,18 +97,26 @@ export function registerCopilotContextProviders( copilotLanguageServerExtensionCapabilitiesFileName ); const capabilitiesContent = await readJsonSync(capabilitiesFilePath); - if ( - capabilitiesContent?.capabilities?.find( - (capability: any) => - capability?.method === resolveContextMethodName && - capability?.version === resolveContextMethodSupportedVersion - ) - ) { - hasCapabilities = true; + for (const capability of capabilitiesContent?.capabilities ?? []) { + if ( + capability.method === oldResolveContextMethodName && + capability.version === oldresolveContextMethodSupportedVersion + ) { + hasCapabilities = 1; + channel.debug(`supported 'roslyn/resolveContext' method found in capabilities.json`); + break; + } else if ( + capability.method === newResolveContextMethodName && + capability.version === newResolveContextMethodSupportedVersion + ) { + hasCapabilities = 2; + channel.debug(`supported 'roslyn/resolveContext@2' method found in capabilities.json`); + break; + } } } - if (!hasCapabilities) { + if (hasCapabilities === 0) { channel.debug( `Failed to find compatible version of context provider from installed version of ${csharpDevkitExtensionId}.` ); @@ -131,11 +151,18 @@ export function registerCopilotContextProviders( if (!contextResolveParam) { return []; } - const items = await languageServer.sendRequest( - resolveContextRequest, - contextResolveParam, - token - ); + const items = + hasCapabilities === 1 + ? await languageServer.sendRequest( + oldResolveContextRequest, + contextResolveParam, + token + ) + : await languageServer.sendRequest( + newResolveContextRequest, + contextResolveParam, + token + ); channel.trace(`Copilot context provider resolved ${items.length} items`); return items; }, diff --git a/test/lsptoolshost/integrationTests/documentSymbolProvider.integration.test.ts b/test/lsptoolshost/integrationTests/documentSymbolProvider.integration.test.ts index 9e489bed97..3d0342f08b 100644 --- a/test/lsptoolshost/integrationTests/documentSymbolProvider.integration.test.ts +++ b/test/lsptoolshost/integrationTests/documentSymbolProvider.integration.test.ts @@ -50,11 +50,11 @@ describe(`Document Symbol Tests`, () => { expect(symbols[0].children[0].kind).toBe(vscode.SymbolKind.Field); // Finalize - expect(symbols[0].children[3].name).toBe('Finalize'); + expect(symbols[0].children[3].name).toBe('~C'); expect(symbols[0].children[3].kind).toBe(vscode.SymbolKind.Method); // Ctor - expect(symbols[0].children[4].name).toBe('.ctor'); + expect(symbols[0].children[4].name).toBe('C'); expect(symbols[0].children[4].kind).toBe(vscode.SymbolKind.Method); // EventHandler E1 @@ -62,17 +62,17 @@ describe(`Document Symbol Tests`, () => { expect(symbols[0].children[5].kind).toBe(vscode.SymbolKind.Event); // explicit operator int(C c1) - expect(symbols[0].children[11].name).toBe('op_Explicit'); + expect(symbols[0].children[11].name).toBe('explicit operator Int32'); expect(symbols[0].children[11].detail).toBe('explicit operator int(C c1)'); expect(symbols[0].children[11].kind).toBe(vscode.SymbolKind.Operator); // implicit operator int(C c1) - expect(symbols[0].children[12].name).toBe('op_Implicit'); + expect(symbols[0].children[12].name).toBe('implicit operator C'); expect(symbols[0].children[12].detail).toBe('implicit operator C(int i)'); expect(symbols[0].children[12].kind).toBe(vscode.SymbolKind.Operator); // implicit operator int(C c1) - expect(symbols[0].children[12].name).toBe('op_Implicit'); + expect(symbols[0].children[12].name).toBe('implicit operator C'); expect(symbols[0].children[12].detail).toBe('implicit operator C(int i)'); expect(symbols[0].children[12].kind).toBe(vscode.SymbolKind.Operator); @@ -82,7 +82,7 @@ describe(`Document Symbol Tests`, () => { expect(symbols[0].children[13].kind).toBe(vscode.SymbolKind.Method); // operator != - expect(symbols[0].children[14].name).toBe('op_Inequality'); + expect(symbols[0].children[14].name).toBe('operator !='); expect(symbols[0].children[14].detail).toBe('operator !=(C c1, int i)'); expect(symbols[0].children[14].kind).toBe(vscode.SymbolKind.Operator);