Path: blob/main/extensions/copilot/src/extension/inlineEdits/vscode-node/similarFilesContext.ts
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { getSimilarFilesOptions } from '../../completions-core/vscode-node/lib/src/experiments/similarFileOptionsProvider';6import { getPromptOptions } from '../../completions-core/vscode-node/lib/src/prompt/prompt';7import { NeighborSource } from '../../completions-core/vscode-node/lib/src/prompt/similarFiles/neighborFiles';8import { TelemetryWithExp } from '../../completions-core/vscode-node/lib/src/telemetry';9import { ICompletionsTextDocumentManagerService } from '../../completions-core/vscode-node/lib/src/textDocumentManager';10import { DocumentInfoWithOffset } from '../../completions-core/vscode-node/prompt/src/prompt';11import { getSimilarSnippets } from '../../completions-core/vscode-node/prompt/src/snippetInclusion/similarFiles';12import { SnippetWithProviderInfo } from '../../completions-core/vscode-node/prompt/src/snippetInclusion/snippets';13import { ICopilotInlineCompletionItemProviderService } from '../../completions/common/copilotInlineCompletionItemProviderService';14import { LineRange0Based } from '../../xtab/common/lineRange';15import { INeighborFileSnippet, ISimilarFilesContextService } from '../../xtab/common/similarFilesContextService';1617type RankedSnippet = SnippetWithProviderInfo & { relativePath?: string };1819export class SimilarFilesContextService implements ISimilarFilesContextService {2021readonly _serviceBrand: undefined;2223constructor(24@ICopilotInlineCompletionItemProviderService private readonly _copilotService: ICopilotInlineCompletionItemProviderService,25) { }2627async compute(uri: string, languageId: string, source: string, cursorOffset: number): Promise<string | undefined> {28try {29const result = await this._gatherSnippets(uri, languageId, source, cursorOffset);30if (!result) {31return undefined;32}33const { neighborFileCount, snippets } = result;34return JSON.stringify({35neighborFileCount,36snippets: snippets.map(s => ({37score: s.score,38startLine: s.startLine,39endLine: s.endLine,40relativePath: s.relativePath,41snippet: s.snippet,42})),43});44} catch {45return undefined;46}47}4849async getSnippetsForPrompt(uri: string, languageId: string, source: string, cursorOffset: number): Promise<readonly INeighborFileSnippet[] | undefined> {50try {51const result = await this._gatherSnippets(uri, languageId, source, cursorOffset);52if (!result) {53return undefined;54}55const { snippets, relativePathToUri } = result;56return snippets.map(s => ({57uri: (s.relativePath && relativePathToUri.get(s.relativePath)) ?? uri,58relativePath: s.relativePath,59snippet: s.snippet,60lineRange: new LineRange0Based(s.startLine, s.endLine),61score: s.score,62}));63} catch {64return undefined;65}66}6768private async _gatherSnippets(uri: string, languageId: string, source: string, cursorOffset: number): Promise<{ neighborFileCount: number; snippets: RankedSnippet[]; relativePathToUri: Map<string, string> } | undefined> {69const completionsInstaService = this._copilotService.getOrCreateInstantiationService();70const telemetryData = TelemetryWithExp.createEmptyConfigForTesting();7172const { docs } = await completionsInstaService.invokeFunction(73accessor => NeighborSource.getNeighborFilesAndTraits(accessor, uri, languageId, telemetryData)74);7576const promptOptions = completionsInstaService.invokeFunction(getPromptOptions, telemetryData, languageId);77const similarFilesOptions =78promptOptions.similarFilesOptions ||79completionsInstaService.invokeFunction(getSimilarFilesOptions, telemetryData, languageId);8081const tdm = completionsInstaService.invokeFunction(accessor => accessor.get(ICompletionsTextDocumentManagerService));82const relativePath = tdm.getRelativePath({ uri });8384const docInfo: DocumentInfoWithOffset = {85uri,86source,87languageId,88offset: cursorOffset,89relativePath,90};9192const neighborDocs = Array.from(docs.values());93const relativePathToUri = new Map<string, string>();94for (const doc of neighborDocs) {95if (doc.relativePath) {96relativePathToUri.set(doc.relativePath, doc.uri);97}98}99100const snippets = (await getSimilarSnippets(101docInfo,102neighborDocs,103similarFilesOptions,104))105.filter(s => s.snippet.length > 0)106.sort((a, b) => a.score - b.score);107108return { neighborFileCount: docs.size, snippets, relativePathToUri };109}110}111112113