Skip to content

Commit 4901caa

Browse files
committed
feat(chat): add /listPatches command
1 parent 3863843 commit 4901caa

File tree

4 files changed

+126
-1
lines changed

4 files changed

+126
-1
lines changed

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@
5252
"name": "findUpstreamFiles",
5353
"description": "Attempt to find upstream Chromium files that Electron files are derived from."
5454
},
55+
{
56+
"name": "listPatches",
57+
"description": "List the patches that touch a given filename."
58+
},
5559
{
5660
"name": "upgradesFindCL",
5761
"description": "Attempt to find the Chromium CL related to the current sync/build failure."

src/chat/commands/listPatches.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import path from "node:path";
2+
3+
import * as vscode from "vscode";
4+
5+
import { type ElectronPatchesProvider } from "../../views/patches";
6+
7+
async function fileExists(uri: vscode.Uri): Promise<boolean> {
8+
try {
9+
await vscode.workspace.fs.stat(uri);
10+
return true;
11+
} catch {
12+
return false;
13+
}
14+
}
15+
16+
export async function listPatches(
17+
chromiumRoot: vscode.Uri,
18+
electronRoot: vscode.Uri,
19+
patchesProvider: ElectronPatchesProvider,
20+
request: vscode.ChatRequest,
21+
stream: vscode.ChatResponseStream,
22+
token: vscode.CancellationToken,
23+
) {
24+
// Find the file the user is asking about
25+
const filename = request.prompt.trim();
26+
let patchedFile: vscode.Uri;
27+
28+
const absoluteFileUri = vscode.Uri.file(filename);
29+
const chromiumRelativeFileUri = vscode.Uri.joinPath(chromiumRoot, filename);
30+
31+
if (await fileExists(absoluteFileUri)) {
32+
patchedFile = absoluteFileUri;
33+
} else if (await fileExists(chromiumRelativeFileUri)) {
34+
patchedFile = chromiumRelativeFileUri;
35+
} else {
36+
stream.markdown("File not found");
37+
return;
38+
}
39+
40+
const patches = await vscode.workspace.findFiles(
41+
new vscode.RelativePattern(
42+
vscode.Uri.joinPath(electronRoot, "patches"),
43+
"**/*.patch",
44+
),
45+
null,
46+
undefined,
47+
token,
48+
);
49+
50+
const matchingPatches = new Map<string, string[]>();
51+
52+
for (const patch of patches) {
53+
const patchDirectory = vscode.Uri.file(path.dirname(patch.fsPath));
54+
const checkoutDirectory =
55+
await patchesProvider.getCheckoutDirectoryForPatchDirectory(
56+
patchDirectory,
57+
);
58+
const relativeFilename = path.relative(
59+
checkoutDirectory.fsPath,
60+
patchedFile.fsPath,
61+
);
62+
63+
if (relativeFilename.startsWith("..")) {
64+
continue;
65+
}
66+
67+
const contents = (await vscode.workspace.fs.readFile(patch)).toString();
68+
if (
69+
contents.includes(
70+
`diff --git a/${relativeFilename} b/${relativeFilename}`,
71+
)
72+
) {
73+
const patchDirectoryName = path.basename(patchDirectory.fsPath);
74+
if (!matchingPatches.has(patchDirectoryName)) {
75+
matchingPatches.set(patchDirectoryName, []);
76+
}
77+
matchingPatches
78+
.get(patchDirectoryName)!
79+
.push(path.basename(patch.fsPath));
80+
}
81+
}
82+
83+
if (matchingPatches.size === 0) {
84+
stream.markdown("No patches found");
85+
return;
86+
}
87+
88+
stream.markdown("Found the following patches for ");
89+
stream.anchor(patchedFile);
90+
stream.markdown(":\n");
91+
92+
// Output the final file tree
93+
stream.filetree(
94+
[
95+
{
96+
name: "patches",
97+
children: Array.from(matchingPatches.entries()).map(
98+
([patchDirectory, patches]) => {
99+
return {
100+
name: patchDirectory,
101+
children: patches.map((patch) => ({ name: patch })),
102+
};
103+
},
104+
),
105+
},
106+
],
107+
electronRoot,
108+
);
109+
}

src/chat/participant.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import * as vscode from "vscode";
22

33
import { chatParticipantId } from "../constants";
4+
import { type ElectronPatchesProvider } from "../views/patches";
45

56
import { findUpstreamFiles } from "./commands/findUpstreamFiles";
7+
import { listPatches } from "./commands/listPatches";
68
import { upgradesFindCL } from "./commands/upgradesFindCL";
79
import { searchCLs } from "./commands/searchCLs";
810
import { getPrivateTools } from "./tools";
911

1012
export function registerChatParticipant(
1113
{ extension, extensionUri }: vscode.ExtensionContext,
1214
electronRoot: vscode.Uri,
15+
patchesProvider: ElectronPatchesProvider,
1316
) {
1417
const chromiumRoot = vscode.Uri.joinPath(electronRoot, "..");
1518

@@ -24,6 +27,15 @@ export function registerChatParticipant(
2427
if (request.command === "findUpstreamFiles") {
2528
await findUpstreamFiles(chromiumRoot, request, stream, token);
2629
return {};
30+
} else if (request.command === "listPatches") {
31+
await listPatches(
32+
chromiumRoot,
33+
electronRoot,
34+
patchesProvider,
35+
request,
36+
stream,
37+
token,
38+
);
2739
} else if (
2840
request.command === "upgradesFindCL" ||
2941
request.command === "upgradesFindCLAdvanced"

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ export async function activate(context: vscode.ExtensionContext) {
499499
new DocsLinkCompletionProvider(linkableProvider),
500500
...DocsLinkCompletionProvider.TRIGGER_CHARACTERS,
501501
),
502-
registerChatParticipant(context, electronRoot),
502+
registerChatParticipant(context, electronRoot, patchesProvider),
503503
);
504504
registerElectronBuildToolsCommands(
505505
context,

0 commit comments

Comments
 (0)