Path: blob/main/extensions/copilot/src/extension/chatSessions/vscode-node/prContentProvider.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 * as l10n from '@vscode/l10n';6import * as vscode from 'vscode';7import { IOctoKitService, PullRequestFile } from '../../../platform/github/common/githubService';8import { ILogService } from '../../../platform/log/common/logService';9import { Disposable } from '../../../util/vs/base/common/lifecycle';1011/**12* URI scheme for PR content13*/14export const PR_SCHEME = 'copilot-pr';1516/**17* Parameters encoded in PR content URIs18*/19export interface PRContentUriParams {20owner: string;21repo: string;22prNumber: number;23fileName: string;24commitSha: string;25isBase: boolean; // true for left side, false for right side26previousFileName?: string; // for renames27status?: PullRequestFile['status'];28}2930/**31* Create a URI for PR file content32*/33export function toPRContentUri(34fileName: string,35params: Omit<PRContentUriParams, 'fileName'>36): vscode.Uri {37return vscode.Uri.from({38scheme: PR_SCHEME,39path: `/${fileName}`,40query: JSON.stringify({ ...params, fileName })41});42}4344/**45* Parse parameters from a PR content URI46*/47export function fromPRContentUri(uri: vscode.Uri): PRContentUriParams | undefined {48if (uri.scheme !== PR_SCHEME) {49return undefined;50}51try {52return JSON.parse(uri.query) as PRContentUriParams;53} catch (e) {54return undefined;55}56}5758function isMissingOnSide(status: PullRequestFile['status'] | undefined, isBase: boolean): boolean {59if (!status) {60return false;61}62if (isBase) {63return status === 'added';64}65return status === 'removed';66}6768/**69* TextDocumentContentProvider for PR content that fetches file content from GitHub70*/71export class PRContentProvider extends Disposable implements vscode.TextDocumentContentProvider {72private static readonly ID = 'PRContentProvider';73private _onDidChange = this._register(new vscode.EventEmitter<vscode.Uri>());74readonly onDidChange = this._onDidChange.event;7576constructor(77@IOctoKitService private readonly _octoKitService: IOctoKitService,78@ILogService private readonly logService: ILogService,79) {80super();8182// Register text document content provider for PR scheme83this._register(84vscode.workspace.registerTextDocumentContentProvider(85PR_SCHEME,86this87)88);89}9091async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {92const params = fromPRContentUri(uri);93if (!params) {94this.logService.error(`[${PRContentProvider.ID}] Invalid PR content URI: ${uri.toString()}`);95return '';96}9798if (isMissingOnSide(params.status, params.isBase)) {99this.logService.trace(100`[${PRContentProvider.ID}] Skipping fetch for ${params.fileName} because it does not exist on the ${params.isBase ? 'base' : 'head'} side (status: ${params.status})`101);102return '';103}104105try {106this.logService.trace(107`[${PRContentProvider.ID}] Fetching ${params.isBase ? 'base' : 'head'} content for ${params.fileName} ` +108`from ${params.owner}/${params.repo}#${params.prNumber} at ${params.commitSha}`109);110111// Fetch file content from GitHub112const content = await this._octoKitService.getFileContent(113params.owner,114params.repo,115params.commitSha,116params.fileName,117{ createIfNone: { detail: l10n.t('Sign in to GitHub to access Copilot cloud sessions.') } }118);119120return content;121} catch (error) {122this.logService.error(123`[${PRContentProvider.ID}] Failed to fetch PR file content: ${error instanceof Error ? error.message : String(error)}`124);125// Return empty content instead of throwing to avoid breaking the diff view126return '';127}128}129}130131132