дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
* feat(nav): Complete file paths and flag unresolved web file references Path completion in href/src/url()/@import, Markdown links and path-like strings, folders first. HTML and CSS paths that name no file get a 'Cannot resolve file' warning. File references resolve in the backend like IDEA's: relative to the file, /-rooted against the project and resource roots. * feat: Align editor, workbench, run/debug and VCS interactions with IntelliJ IDEA Keymap - Let AltGr characters through instead of firing Ctrl+Alt shortcuts (Windows/Linux) - Double Shift: strict press/release timing, ignored while typing or after Shift+click - Chords wait 2s and swallow an unmatched second stroke - Drop CodeMirror defaults that clash with IDEA keys; ⌘Enter is Split Line, add Scroll to Center and Code Block Start/End - Add missing IDEA defaults (⌃J, ⌘Y, ⇧⌘C, ⌥⌘Y, ⇧⌘M, F9 Resume, ⌘R Rerun, …) Editor - Tab inserts at the caret; smart Backspace to the proper indent; Enter continues a `//` comment; per-language line comment placement - Back/Forward records navigations only; ⌘F searches the selected text - In-place rename; ⌃Space inserts a sole candidate; commit characters only for a focused lookup; usage highlighting survives edits; ⌥Enter offers fixes from the caret line; ⌘-hover shows declaration info only for navigable targets Workbench - Tool windows: primary and split area per side, six Move To anchors, layout migration - ⌘W closes tool window content; Shift+Esc from the editor; closing a tab activates the left neighbour; preview tab and tab limit follow IDEA defaults - Switcher lists open editors and tool windows; Recent Files Delete removes items - Search Everywhere tab/scope behaviour; popups close when the window deactivates - Project view: Copy/Move dialogs on paste, skippable usage search on delete, new-file input cancels on blur; Settings search Esc clears the filter - Status bar breadcrumbs open a children popup; notification timeouts Run / Debug / Build / Terminal - Run asks to stop a running single-instance config; Rerun restarts silently; "Allow multiple instances" option - Run chooser: Enter runs, Shift debugs, F4/Delete/digits - Type into the console for stdin; Stop covers debug sessions - Log (Shift+click) and temporary (Alt+click) breakpoints; independent suspend/log options; Evaluate prefill and history; changed-value highlighting; expandable hints - Build window opens on failure and jumps to the first error - Terminal confirms closing a busy tab and lets IDE shortcuts through VCS - Correct ours/theirs labels during rebase, cherry-pick and revert - Smart/Force Checkout; remote branch checkout updates the local branch - Partial commit by changed block; inline before-commit check results - F7 continues into the next file; Rollback Lines; Commit and Push; Amend message swap - Branch delete with Restore; force push confirmation; editable push target; update summary with the incoming commits * chore: Regenerate bindings
88 рядки
3.5 KiB
TypeScript
88 рядки
3.5 KiB
TypeScript
import { afterEach, describe, expect, it } from "vitest";
|
|
import { act, fireEvent, render, screen } from "@testing-library/react";
|
|
import { usePlatform } from "@/platform/platformInfo";
|
|
import { ask, confirmChecked, MessagesHost, type MessageResult } from "./messages";
|
|
|
|
function askUsagesDetected() {
|
|
let result: MessageResult | undefined;
|
|
act(() => {
|
|
void ask({
|
|
title: "Usages Detected",
|
|
body: "Function 'unused' has 1 usage that is not safe to delete.",
|
|
buttons: [
|
|
{ id: "view", label: "View Usages", primary: true },
|
|
{ id: "delete", label: "Delete Anyway" },
|
|
],
|
|
}).then((r) => (result = r));
|
|
});
|
|
return () => result;
|
|
}
|
|
|
|
const footerLabels = () =>
|
|
[...screen.getByRole("dialog").querySelectorAll("[data-dialog-footer] button")].map((b) => b.textContent);
|
|
|
|
describe("message dialogs", () => {
|
|
const os = usePlatform.getState().os;
|
|
afterEach(() => usePlatform.setState({ os }));
|
|
|
|
it("macOS: Cancel · Delete Anyway · View Usages (default rightmost, focused); Enter picks the default", async () => {
|
|
usePlatform.setState({ os: "macos" });
|
|
render(<MessagesHost />);
|
|
const result = askUsagesDetected();
|
|
expect(footerLabels()).toEqual(["Cancel", "Delete Anyway", "View Usages"]);
|
|
expect(document.activeElement).toBe(screen.getByRole("button", { name: "View Usages" }));
|
|
await act(async () => void fireEvent.keyDown(screen.getByRole("dialog"), { key: "Enter" }));
|
|
expect(result()).toEqual({ button: "view", checked: false });
|
|
expect(screen.queryByRole("dialog")).toBeNull();
|
|
});
|
|
|
|
it("Windows: View Usages · Delete Anyway · Cancel; Escape and Cancel cancel", async () => {
|
|
usePlatform.setState({ os: "windows" });
|
|
render(<MessagesHost />);
|
|
let result = askUsagesDetected();
|
|
expect(footerLabels()).toEqual(["View Usages", "Delete Anyway", "Cancel"]);
|
|
await act(async () => void fireEvent.keyDown(document.body, { key: "Escape" }));
|
|
expect(result()?.button).toBe("cancel");
|
|
result = askUsagesDetected();
|
|
await act(async () => void fireEvent.click(screen.getByRole("button", { name: "Cancel" })));
|
|
expect(result()?.button).toBe("cancel");
|
|
expect(screen.queryByRole("dialog")).toBeNull();
|
|
});
|
|
|
|
it("reports the checkbox with the chosen button", async () => {
|
|
render(<MessagesHost />);
|
|
let result: { checked: boolean } | null | undefined;
|
|
act(() => {
|
|
void confirmChecked({
|
|
title: "Delete Image",
|
|
message: "Delete image 'x'?",
|
|
ok: "Delete",
|
|
checkbox: "Force",
|
|
}).then((r) => (result = r));
|
|
});
|
|
fireEvent.click(screen.getByRole("checkbox", { name: "Force" }));
|
|
await act(async () => void fireEvent.click(screen.getByRole("button", { name: "Delete" })));
|
|
expect(result).toEqual({ checked: true });
|
|
});
|
|
|
|
it("starts with the given checkbox state and can be dismissed from outside", async () => {
|
|
render(<MessagesHost />);
|
|
const abort = new AbortController();
|
|
let result: MessageResult | undefined;
|
|
act(() => {
|
|
void ask({
|
|
title: "Delete",
|
|
body: "Delete 'a'?",
|
|
checkbox: "Safe delete",
|
|
checked: true,
|
|
signal: abort.signal,
|
|
buttons: [{ id: "ok", label: "Delete", primary: true }],
|
|
}).then((r) => (result = r));
|
|
});
|
|
expect(screen.getByRole("checkbox", { name: "Safe delete" })).toBeChecked();
|
|
await act(async () => abort.abort());
|
|
expect(result).toEqual({ button: "dismissed", checked: true });
|
|
expect(screen.queryByRole("dialog")).toBeNull();
|
|
});
|
|
});
|