Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/chatSessions/vscode-node/prContentProvider.ts
13399 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as l10n from '@vscode/l10n';
7
import * as vscode from 'vscode';
8
import { IOctoKitService, PullRequestFile } from '../../../platform/github/common/githubService';
9
import { ILogService } from '../../../platform/log/common/logService';
10
import { Disposable } from '../../../util/vs/base/common/lifecycle';
11
12
/**
13
* URI scheme for PR content
14
*/
15
export const PR_SCHEME = 'copilot-pr';
16
17
/**
18
* Parameters encoded in PR content URIs
19
*/
20
export interface PRContentUriParams {
21
owner: string;
22
repo: string;
23
prNumber: number;
24
fileName: string;
25
commitSha: string;
26
isBase: boolean; // true for left side, false for right side
27
previousFileName?: string; // for renames
28
status?: PullRequestFile['status'];
29
}
30
31
/**
32
* Create a URI for PR file content
33
*/
34
export function toPRContentUri(
35
fileName: string,
36
params: Omit<PRContentUriParams, 'fileName'>
37
): vscode.Uri {
38
return vscode.Uri.from({
39
scheme: PR_SCHEME,
40
path: `/${fileName}`,
41
query: JSON.stringify({ ...params, fileName })
42
});
43
}
44
45
/**
46
* Parse parameters from a PR content URI
47
*/
48
export function fromPRContentUri(uri: vscode.Uri): PRContentUriParams | undefined {
49
if (uri.scheme !== PR_SCHEME) {
50
return undefined;
51
}
52
try {
53
return JSON.parse(uri.query) as PRContentUriParams;
54
} catch (e) {
55
return undefined;
56
}
57
}
58
59
function isMissingOnSide(status: PullRequestFile['status'] | undefined, isBase: boolean): boolean {
60
if (!status) {
61
return false;
62
}
63
if (isBase) {
64
return status === 'added';
65
}
66
return status === 'removed';
67
}
68
69
/**
70
* TextDocumentContentProvider for PR content that fetches file content from GitHub
71
*/
72
export class PRContentProvider extends Disposable implements vscode.TextDocumentContentProvider {
73
private static readonly ID = 'PRContentProvider';
74
private _onDidChange = this._register(new vscode.EventEmitter<vscode.Uri>());
75
readonly onDidChange = this._onDidChange.event;
76
77
constructor(
78
@IOctoKitService private readonly _octoKitService: IOctoKitService,
79
@ILogService private readonly logService: ILogService,
80
) {
81
super();
82
83
// Register text document content provider for PR scheme
84
this._register(
85
vscode.workspace.registerTextDocumentContentProvider(
86
PR_SCHEME,
87
this
88
)
89
);
90
}
91
92
async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {
93
const params = fromPRContentUri(uri);
94
if (!params) {
95
this.logService.error(`[${PRContentProvider.ID}] Invalid PR content URI: ${uri.toString()}`);
96
return '';
97
}
98
99
if (isMissingOnSide(params.status, params.isBase)) {
100
this.logService.trace(
101
`[${PRContentProvider.ID}] Skipping fetch for ${params.fileName} because it does not exist on the ${params.isBase ? 'base' : 'head'} side (status: ${params.status})`
102
);
103
return '';
104
}
105
106
try {
107
this.logService.trace(
108
`[${PRContentProvider.ID}] Fetching ${params.isBase ? 'base' : 'head'} content for ${params.fileName} ` +
109
`from ${params.owner}/${params.repo}#${params.prNumber} at ${params.commitSha}`
110
);
111
112
// Fetch file content from GitHub
113
const content = await this._octoKitService.getFileContent(
114
params.owner,
115
params.repo,
116
params.commitSha,
117
params.fileName,
118
{ createIfNone: { detail: l10n.t('Sign in to GitHub to access Copilot cloud sessions.') } }
119
);
120
121
return content;
122
} catch (error) {
123
this.logService.error(
124
`[${PRContentProvider.ID}] Failed to fetch PR file content: ${error instanceof Error ? error.message : String(error)}`
125
);
126
// Return empty content instead of throwing to avoid breaking the diff view
127
return '';
128
}
129
}
130
}
131
132