mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 00:45:54 +00:00
feat(java): Add Project JDK and Maven home / settings.xml / local repository settings
The JDK was always picked automatically (JAVA_HOME, PATH, the usual install dirs, by the module's Java version) and Maven was the project's mvnw or mvn on PATH, with no way to override either. languages.java.jdk (Languages & Frameworks › Java › Project JDK) now sets the default jdtls runtime, the JDK of Run/Debug and JAVA_HOME for Maven and Gradle; languages.java.maven (Build Tools › Maven) sets the Maven home, -s and -Dmaven.repo.local for sync, builds, tool-window goals and detected run configurations. JDKs and Maven installations are detected for the pickers. Closes #13
This commit is contained in:
1 parent
c59f93988b
commit
7fa1d08b94
22 files changed
+484
-48
No files matched your search
+25
-1
@@ -249,6 +249,7 @@ export const commands = {
|
||||
* follow-up command. Edits the server requests arrive via `workspace/applyEdit`.
|
||||
*/
|
||||
lspExecuteCommand: (doc: DocId, command: Command) => typedError<null, IdeError>(__TAURI_INVOKE("lsp_execute_command", { doc, command })),
|
||||
/** Changes of every repository of the project. */
|
||||
vcsStatus: () => typedError<FileStatus[], IdeError>(__TAURI_INVOKE("vcs_status")),
|
||||
vcsBranchInfo: () => typedError<BranchInfo, IdeError>(__TAURI_INVOKE("vcs_branch_info")),
|
||||
/** Gutter change markers for a file, computed against its current (unsaved) text. */
|
||||
@@ -2341,11 +2342,18 @@ export type JavaLaunchInfo = {
|
||||
};
|
||||
|
||||
export type JavaSettings = {
|
||||
/**
|
||||
* Project JDK home; empty = per module, the installed JDK matching the
|
||||
* Java version it targets.
|
||||
*/
|
||||
jdk?: string,
|
||||
/**
|
||||
* Extra JVM options for the Java language server (jdtls), space-separated
|
||||
* (VS Code's `java.jdt.ls.vmargs`).
|
||||
*/
|
||||
jdtlsVmArgs?: string,
|
||||
/** Build Tools › Maven. */
|
||||
maven?: MavenSettings,
|
||||
};
|
||||
|
||||
/** Editor › Code Style › <Language> › Tabs and Indents (unset fields inherit). */
|
||||
@@ -2635,10 +2643,22 @@ export type MavenProject = {
|
||||
javaVersion: number | null,
|
||||
/** Maven launcher: the nearest `mvnw` up to the project root (absolute), else `mvn`. */
|
||||
command: string,
|
||||
/** Options before the goals (`-s`, `-Dmaven.repo.local=`); filled in by the shell from settings. */
|
||||
options: string[],
|
||||
/** Environment for runs (`JAVA_HOME` of the matching JDK); filled in by the shell. */
|
||||
env: { [key in string]: string },
|
||||
};
|
||||
|
||||
/** Build Tools › Maven. */
|
||||
export type MavenSettings = {
|
||||
/** Maven home (or its `mvn` executable); empty = the project's `mvnw`, else `mvn` on `PATH`. */
|
||||
home?: string,
|
||||
/** User `settings.xml` (`-s`); empty = `~/.m2/settings.xml`. */
|
||||
userSettings?: string,
|
||||
/** Local repository (`-Dmaven.repo.local`); empty = from `settings.xml`. */
|
||||
localRepository?: string,
|
||||
};
|
||||
|
||||
export type MemoryCategory =
|
||||
/** The backend and its WebView processes. */
|
||||
"app" | "languageServer" |
|
||||
@@ -3281,7 +3301,11 @@ export type Sdk = {
|
||||
/** What [`detect`] looks for. */
|
||||
export type SdkKind = "python" | "node" |
|
||||
/** npm / pnpm / yarn executables. */
|
||||
"packageManager" | "rust" | "go" | "typeScript";
|
||||
"packageManager" | "rust" | "go" | "typeScript" |
|
||||
/** JDK homes. */
|
||||
"jdk" |
|
||||
/** Maven homes. */
|
||||
"maven";
|
||||
|
||||
export type SearchEvent = { type: "file"; file: FileMatches } | { type: "done"; summary: SearchSummary };
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ const mavenModel: BuildModel = {
|
||||
profiles: ["ci"],
|
||||
javaVersion: 21,
|
||||
command: "/p/mvnw",
|
||||
options: [],
|
||||
env: {},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -95,6 +95,10 @@ export function activate(): () => void {
|
||||
if ([...e.created, ...e.modified, ...e.removed].some((p) => BUILD_FILE.test(p))) scheduleLoad();
|
||||
}),
|
||||
onIdeEvent("projectRootsChanged", scheduleLoad),
|
||||
// Project JDK / Maven home and options are applied to the model's launchers.
|
||||
onIdeEvent("settingsChanged", (e) => {
|
||||
if (e.key === "languages" || e.key.startsWith("languages.java")) scheduleLoad();
|
||||
}),
|
||||
registerActions([
|
||||
{
|
||||
id: "maven.reload",
|
||||
|
||||
@@ -37,6 +37,7 @@ function project(over: Partial<MavenProject>): MavenProject {
|
||||
profiles: [],
|
||||
javaVersion: 21,
|
||||
command: "/p/mvnw",
|
||||
options: [],
|
||||
env: { JAVA_HOME: "/jdk21" },
|
||||
...over,
|
||||
};
|
||||
@@ -184,6 +185,11 @@ describe("Maven runs", () => {
|
||||
const root = mavenGoalConfig(maven.projects[0]!, ["clean"], maven, { offline: false, skipTests: false, profiles: {} });
|
||||
expect(root.cwd).toBeNull();
|
||||
expect(root.isTest).toBe(false);
|
||||
// Settings › Maven options go before the goals.
|
||||
const configured = { ...core, options: ["-s", "/m2/settings.xml"] };
|
||||
expect(mavenGoalConfig(configured, ["test"], maven, { offline: false, skipTests: true, profiles: {} }).args).toEqual(
|
||||
["-s", "/m2/settings.xml", "test", "-DskipTests"],
|
||||
);
|
||||
});
|
||||
|
||||
it("parses typed command lines", () => {
|
||||
|
||||
@@ -401,7 +401,7 @@ export function mavenGoalConfig(
|
||||
model: Pick<MavenModel, "profiles">,
|
||||
options: MavenRunOptions,
|
||||
): RunConfig {
|
||||
const args = mavenArgs(goals, model, options);
|
||||
const args = [...project.options, ...mavenArgs(goals, model, options)];
|
||||
return {
|
||||
id: `maven:goal:${project.pom}:${goals.join(" ")}`,
|
||||
name: mavenConfigName(project, goals),
|
||||
|
||||
@@ -21,7 +21,7 @@ describe("languages settings", () => {
|
||||
node: { packageManager: "pip" },
|
||||
rust: { checkCommand: "clippy", checkOnSave: false },
|
||||
typescript: { version: "" },
|
||||
java: { jdtlsVmArgs: " -Xmx2g " },
|
||||
java: { jdtlsVmArgs: " -Xmx2g ", jdk: 21, maven: { home: " /opt/maven " } },
|
||||
});
|
||||
expect(v.python).toEqual({ interpreter: "/usr/bin/python3", activateVirtualenv: true });
|
||||
expect(v.node.packageManager).toBe("");
|
||||
@@ -29,6 +29,8 @@ describe("languages settings", () => {
|
||||
expect(v.rust.checkOnSave).toBe(false);
|
||||
expect(v.typescript.version).toBe("bundled");
|
||||
expect(v.java.jdtlsVmArgs).toBe("-Xmx2g");
|
||||
expect(v.java.jdk).toBe("");
|
||||
expect(v.java.maven).toEqual({ home: "/opt/maven", userSettings: "", localRepository: "" });
|
||||
expect(validateSettings({}).languages).toEqual(DEFAULT_LANGUAGES);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Settings › Languages & Frameworks › Go / Java / Node.js / Rust / TypeScript: the
|
||||
* toolchain each language's server and run configurations use (applied by
|
||||
* `ide-sdk` when language servers start and when run configurations load).
|
||||
* Settings › Languages & Frameworks › Go / Java / Node.js / Rust / TypeScript and
|
||||
* Build Tools › Maven: the toolchain each language's server and run configurations
|
||||
* use (applied by `ide-sdk` when language servers start and when run configurations load).
|
||||
*/
|
||||
import { useId, useMemo } from "react";
|
||||
import { IconButton, Input, type SelectOption } from "@/ui";
|
||||
@@ -16,12 +16,15 @@ function PathInput({
|
||||
placeholder,
|
||||
hint,
|
||||
title,
|
||||
file,
|
||||
}: {
|
||||
k: string;
|
||||
label: string;
|
||||
placeholder: string;
|
||||
hint?: string;
|
||||
title: string;
|
||||
/** Browse for a file instead of a directory. */
|
||||
file?: boolean;
|
||||
}) {
|
||||
const [value, set] = useProjectSetting<string>(k);
|
||||
const id = useId();
|
||||
@@ -41,7 +44,7 @@ function PathInput({
|
||||
size="small"
|
||||
title="Browse…"
|
||||
onClick={async () => {
|
||||
const p = await choosePath({ directory: true, title, defaultPath: value || undefined });
|
||||
const p = await choosePath({ directory: !file, title, defaultPath: value || undefined });
|
||||
if (p) set(p);
|
||||
}}
|
||||
/>
|
||||
@@ -217,6 +220,19 @@ export function JavaPage() {
|
||||
const id = useId();
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<Section title="Project JDK">
|
||||
<SdkRow
|
||||
k="languages.java.jdk"
|
||||
label="SDK"
|
||||
kind="jdk"
|
||||
emptyLabel="Auto"
|
||||
emptyDetail="per module, the JDK of its Java version"
|
||||
directory
|
||||
browseTitle="Select JDK Home Directory"
|
||||
aria-label="Project JDK"
|
||||
hint="Compiles and runs the project: the default jdtls runtime, Run/Debug, and JAVA_HOME for Maven and Gradle."
|
||||
/>
|
||||
</Section>
|
||||
<Section title="Language Server">
|
||||
<Row
|
||||
label="JVM options"
|
||||
@@ -237,6 +253,44 @@ export function JavaPage() {
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Build Tools › Maven
|
||||
|
||||
export function MavenPage() {
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<Section>
|
||||
<SdkRow
|
||||
k="languages.java.maven.home"
|
||||
label="Maven home path"
|
||||
kind="maven"
|
||||
emptyLabel="Auto"
|
||||
emptyDetail="Maven wrapper, else mvn on PATH"
|
||||
directory
|
||||
browseTitle="Select Maven Home Directory"
|
||||
aria-label="Maven home path"
|
||||
hint="Runs sync, builds and Maven run configurations. A chosen home is used instead of the project's mvnw."
|
||||
/>
|
||||
<PathInput
|
||||
k="languages.java.maven.userSettings"
|
||||
label="User settings file"
|
||||
placeholder="~/.m2/settings.xml"
|
||||
title="Select Maven settings.xml"
|
||||
file
|
||||
hint="Passed as -s (mirrors, servers, proxies)."
|
||||
/>
|
||||
<PathInput
|
||||
k="languages.java.maven.localRepository"
|
||||
label="Local repository"
|
||||
placeholder="From settings.xml, else ~/.m2/repository"
|
||||
title="Select Local Repository"
|
||||
hint="Passed as -Dmaven.repo.local."
|
||||
/>
|
||||
</Section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TypeScript
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/**
|
||||
* Build, Execution, Deployment pages: Console, Debugger (+ Data Views,
|
||||
* Build, Execution, Deployment pages: Maven, Console, Debugger (+ Data Views,
|
||||
* Stepping), Python Debugger and Run/Debug. Consumed by the run and debugger
|
||||
* features (and `ide-run` for encoding / termination timeout).
|
||||
*/
|
||||
import { WORKFLOW_LIMITS } from "@/platform/workflowSettings";
|
||||
import type { SelectOption } from "@/ui";
|
||||
import { GlobListEditor, NumberInput, Row } from "../components/Form";
|
||||
import { MavenPage } from "../languages/LanguagePages";
|
||||
import { useSetting } from "../components/context";
|
||||
import type { PageSpec } from "./spec";
|
||||
import { Indented, ToggleNumber } from "./workflowControls";
|
||||
@@ -89,6 +90,15 @@ function TooltipDelayRow() {
|
||||
}
|
||||
|
||||
export const EXECUTION_PAGES: PageSpec[] = [
|
||||
{
|
||||
id: "build.maven",
|
||||
title: "Maven",
|
||||
group: BUILD_GROUP,
|
||||
// IntelliJ IDEA: Build Tools › Maven, before Console / Debugger.
|
||||
order: 359,
|
||||
keywords: ["maven home", "mvn", "mvnw", "wrapper", "settings.xml", "user settings", "local repository", "m2"],
|
||||
component: MavenPage,
|
||||
},
|
||||
{
|
||||
id: "build.console",
|
||||
title: "Console",
|
||||
|
||||
@@ -52,7 +52,17 @@ export const LANGUAGE_PAGES: PageSpec[] = [
|
||||
title: "Java",
|
||||
group: LANGUAGES_GROUP,
|
||||
order: 395,
|
||||
keywords: ["jdtls", "jvm options", "vmargs", "lombok", "javaagent", "eclipse jdt"],
|
||||
keywords: [
|
||||
"jdk",
|
||||
"project sdk",
|
||||
"java home",
|
||||
"jdtls",
|
||||
"jvm options",
|
||||
"vmargs",
|
||||
"lombok",
|
||||
"javaagent",
|
||||
"eclipse jdt",
|
||||
],
|
||||
component: JavaPage,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,7 +11,11 @@ export interface LanguagesValid {
|
||||
rust: { toolchain: string; stdlib: string; checkOnSave: boolean; checkCommand: "check" | "clippy"; rustfmtArgs: string };
|
||||
go: { goroot: string; gopath: string };
|
||||
typescript: { version: string };
|
||||
java: { jdtlsVmArgs: string };
|
||||
java: {
|
||||
jdk: string;
|
||||
jdtlsVmArgs: string;
|
||||
maven: { home: string; userSettings: string; localRepository: string };
|
||||
};
|
||||
}
|
||||
|
||||
export interface ProjectStructureValid {
|
||||
@@ -30,7 +34,7 @@ export const DEFAULT_LANGUAGES: LanguagesValid = {
|
||||
rust: { toolchain: "", stdlib: "", checkOnSave: true, checkCommand: "check", rustfmtArgs: "" },
|
||||
go: { goroot: "", gopath: "" },
|
||||
typescript: { version: "bundled" },
|
||||
java: { jdtlsVmArgs: "" },
|
||||
java: { jdk: "", jdtlsVmArgs: "", maven: { home: "", userSettings: "", localRepository: "" } },
|
||||
};
|
||||
|
||||
export const DEFAULT_PROJECT_STRUCTURE: ProjectStructureValid = {
|
||||
@@ -76,6 +80,7 @@ export function validateLanguages(raw: unknown): LanguagesValid {
|
||||
const go = obj(l.go);
|
||||
const ts = obj(l.typescript);
|
||||
const java = obj(l.java);
|
||||
const maven = obj(java.maven);
|
||||
return {
|
||||
python: {
|
||||
interpreter: text(py.interpreter, d.python.interpreter),
|
||||
@@ -94,7 +99,15 @@ export function validateLanguages(raw: unknown): LanguagesValid {
|
||||
},
|
||||
go: { goroot: text(go.goroot, d.go.goroot), gopath: text(go.gopath, d.go.gopath) },
|
||||
typescript: { version: text(ts.version, d.typescript.version) || d.typescript.version },
|
||||
java: { jdtlsVmArgs: text(java.jdtlsVmArgs, d.java.jdtlsVmArgs) },
|
||||
java: {
|
||||
jdk: text(java.jdk, d.java.jdk),
|
||||
jdtlsVmArgs: text(java.jdtlsVmArgs, d.java.jdtlsVmArgs),
|
||||
maven: {
|
||||
home: text(maven.home, d.java.maven.home),
|
||||
userSettings: text(maven.userSettings, d.java.maven.userSettings),
|
||||
localRepository: text(maven.localRepository, d.java.maven.localRepository),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user