feat(plugins): allow prompts while resolving code actions (#2025)

Closes #1945

Resolving a lazy code action or file action dropped the invoking window, so a plugin couldn't ask the user anything (input, pick, confirm) while building its edit. Resolution now runs with that window, so prompts work during resolution; previews and Actions on Save never prompt, cancellation keeps the text unchanged, and stale edits are rejected. WIT and SDK docs describe the new behaviour; the released API surface is unchanged.

Co-authored-by: arnaud-ritti <[email protected]>
Цей коміт міститься в:
Arnaud Ritti authored and GitHub committed 2026-11-08 02:26:26 +08:00
1 джерело 0b88599463
коміт 9e6cb7b93e
70 files changed
+559 -82

No files matched your search

+34
Переглянути файл
@@ -217,3 +217,37 @@ test("diagnostics underline the range and ⌥⏎ applies the preferred quick fix
const [applied] = await ipcCalls(page, "lsp_execute_code_action");
expect(applied).toMatchObject({ action: { title: "Import 'com.acme.orders.model.Order'" } });
});
test("lazy plugin actions resolve only when invoked, never for their intention preview", async ({
workbench: page,
}) => {
const editor = await openSample(page);
await page.evaluate(() => {
const action = {
title: "Choose translation file",
kind: "quickfix",
isPreferred: true,
disabledReason: null,
edit: null,
command: null,
data: { plugin: "test.interactive-actions", data: "pick", file: false },
server: 0,
};
window.__ipc.handlers.lsp_code_actions = () => [action];
window.__ipc.handlers.lsp_resolve_code_action = () => ({ ...action, data: null, edit: { files: [] } });
window.__ipc.handlers.lsp_execute_code_action = () => [];
});
await editor.locator(".cm-line", { hasText: "val order: Order" }).click();
await page.keyboard.press("Alt+Enter");
const fix = page.getByRole("option", { name: "Choose translation file", exact: true });
await expect(fix).toBeVisible();
await fix.hover();
await expect(page.getByText("Preview isn't available for this action", { exact: true })).toBeVisible();
expect(await ipcCalls(page, "lsp_resolve_code_action")).toHaveLength(0);
expect(await ipcCalls(page, "lsp_execute_code_action")).toHaveLength(0);
await fix.click();
await expect.poll(() => ipcCalls(page, "lsp_resolve_code_action")).toHaveLength(1);
await expect.poll(() => ipcCalls(page, "lsp_execute_code_action")).toHaveLength(1);
const [applied] = await ipcCalls(page, "lsp_execute_code_action");
expect(applied).toMatchObject({ action: { title: "Choose translation file", edit: { files: [] } } });
});