Files
openidea/e2e/configurationNavigation.fixture.ts
T
qiaojianlong c4b87ae09e perf(java): prewarm configuration navigation and share results between hover and click (#947)
Configuration navigation from YAML/properties still waited for a cold index the first
time and repeated the lookup between the ⌘-hover probe and the click.

- Trusted projects with a Maven/Gradle/Eclipse build file start Java shortly after
  opening. Once JDT reports ServiceReady, the app calls the new
  openidea.java.configuration.warmup command: a low-priority background job builds
  the configuration index one project at a time (open YAML/properties modules first),
  waits for workspace builds, has a 30 s budget per project, and only fills free cache
  room.
- Index builds take a cancellable per-project lock instead of one global lock, so a
  background build never delays another project, and a warmed snapshot is dropped
  if the Java model changed meanwhile.
- In YAML/properties the editor underlines the whole key (hyphens and dots
  included), hover and Go to Definition share one bounded request per key, and the
  declaration chooser names the whole key.

Bundle java-usages 1.6.0 is rebuilt reproducibly with build.py against JDT LS
1.63.0-202610191322 (SHA-256 33cfa1bb…). The real-JDT harness checks that the first
lookup reuses the warmed index.

Co-authored-by: qjlqyf <109515705+qjlqyf@users.noreply.github.com>
2026-11-06 12:23:39 +08:00

101 lines
3.8 KiB
TypeScript

/** Real CodeMirror mouse/navigation path with a deliberately slow IPC boundary.
* Semantic correctness and JVM timings live in the real-JDT configuration harness.
*/
import { EditorState } from "@codemirror/state";
import { EditorView } from "@codemirror/view";
import { commands } from "../src/platform/ipc";
import { usePlatform } from "../src/platform/platformInfo";
import { provideEditorService } from "../src/workbench/contributions";
import { lspDoc } from "../src/editor/lsp/lsp";
import { navigationExtension } from "../src/editor/lsp/navigation";
import { hoverExtension } from "../src/editor/lsp/hover";
import { lspTheme } from "../src/editor/lsp/theme";
Object.assign(window, { __TAURI_INTERNALS__: {} });
usePlatform.setState({ os: "macos" });
document.body.innerHTML = `<style>
body { --link: #215cc8; font: 16px monospace; margin: 32px; } button { margin: 12px; }
.cm-editor { border: 1px solid #888; min-height: 160px; font: 18px monospace; }
</style><button id="back">Back to configuration</button><button id="edit">Edit Java target</button>
<div id="config"></div><div id="java" hidden></div>
<output id="requests">0</output><output id="opened"></output>`;
const configHost = document.querySelector<HTMLDivElement>("#config")!;
const javaHost = document.querySelector<HTMLDivElement>("#java")!;
let requests = 0;
let hoverRequests = 0;
let targetLine = 0;
let clickedAt = 0;
const latency: number[] = [];
commands.lspGoto = async () => {
document.querySelector("#requests")!.textContent = String(++requests);
await new Promise((resolve) => setTimeout(resolve, 500));
return {
status: "ok",
data: [
{
path: "/fixture/Settings.java",
uri: null,
range: { start: { line: targetLine, col: 24 }, end: { line: targetLine, col: 31 } },
},
],
};
};
commands.lspHover = async () => {
hoverRequests++;
return {
status: "ok",
data: { contents: { kind: "plaintext", value: "dingtalk.driver-class-name String" }, range: null },
};
};
commands.lspDocumentLinks = async () => ({ status: "ok", data: [] });
commands.lspDocumentHighlights = async () => ({ status: "ok", data: [] });
commands.cancelRequest = async () => ({ status: "ok", data: null });
const java = new EditorView({
parent: javaHost,
state: EditorState.create({
doc: "class Settings { String agentId; }",
extensions: [
lspDoc.of({ doc: 2, path: "/fixture/Settings.java", language: "java", uiMode: "Java", readOnly: false }),
navigationExtension(),
],
}),
});
const config = new EditorView({
parent: configHost,
state: EditorState.create({
doc: "dingtalk:\n driver-class-name: demo\n",
extensions: [
EditorState.languageData.of(() => [{ wordChars: "-" }]),
lspDoc.of({ doc: 1, path: "/fixture/application.yml", language: "yaml", uiMode: "YAML", readOnly: false }),
navigationExtension(),
hoverExtension(),
lspTheme,
],
}),
});
config.contentDOM.addEventListener(
"mousedown",
() => {
clickedAt = performance.now();
},
true,
);
provideEditorService({
openFile: async (path, options) => {
javaHost.hidden = false;
configHost.hidden = true;
java.dispatch({ selection: { anchor: java.state.doc.line((options?.selection?.line ?? 0) + 1).from + 24 } });
document.querySelector("#opened")!.textContent = `${path}:${options?.selection?.line}`;
latency.push(performance.now() - clickedAt);
},
} as Parameters<typeof provideEditorService>[0]);
document.querySelector("#back")!.addEventListener("click", () => {
javaHost.hidden = true;
configHost.hidden = false;
});
document.querySelector("#edit")!.addEventListener("click", () => {
java.dispatch({ changes: { from: 0, insert: "// moved\n" } });
targetLine++;
});
Object.assign(window, { navigationMetrics: () => ({ requests, hoverRequests, latency, injectedServerDelayMs: 500 }) });