fix(files): keep large source previews responsive (#3665)

Large read-only files bypassed the editor's virtualization and eagerly mounted every highlighted token, which could stall the renderer for seconds and consume gigabytes of memory. Route source previews through bounded platform renderers and reject reads above their display budgets before accumulation.
This commit is contained in:
Mohamed Boudra
2026-08-22 10:13:31 +02:00
committed by GitHub
parent 8905ad4160
commit c763b80824
22 changed files with 589 additions and 183 deletions
@@ -372,6 +372,30 @@ describe("WorkspaceFilesSession", () => {
]);
});
test("rejects an over-budget file before opening a binary transfer", async () => {
const cwd = makeDir("workspace-files-read-budget-");
writeFileSync(join(cwd, "notes.txt"), "hello world");
const { subsystem, emitted, binary } = makeSubsystem({ hasBinaryChannel: true });
await subsystem.handleFileExplorerRequest({
type: "file_explorer_request",
cwd,
path: "notes.txt",
mode: "file",
requestId: "req-read-budget",
acceptBinary: true,
maxBytes: 5,
});
expect(binary).toEqual([]);
expect(emitted).toEqual([
expect.objectContaining({
type: "file_explorer_response",
payload: expect.objectContaining({ error: "File is too large to display" }),
}),
]);
});
test("streams a real file larger than the socket limit as paced ordered chunks", async () => {
const cwd = makeDir("workspace-files-large-binary-");
const fileBytes = Buffer.alloc(8 * 1024 * 1024 + 123);
@@ -263,6 +263,12 @@ export class WorkspaceFilesSession {
source,
);
} else {
if (request.maxBytes) {
const file = await getDownloadableFileInfo({ root: cwd, relativePath: requestedPath });
if (file.size > request.maxBytes) {
throw new Error("File is too large to display");
}
}
if (request.acceptBinary && this.host.hasBinaryChannel()) {
await streamExplorerFile({ root: cwd, relativePath: requestedPath }, async (file) => {
await this.host.emitBinary(