Compare commits

..
Author SHA1 Message Date
l0ng-ai aaeaec798c Merge remote-tracking branch 'origin/main' into HEAD 2026-11-01 18:59:17 +08:00
l0ng-ai 49f9c57bcc docs: remove the README build section 2026-11-01 18:46:40 +08:00
l0ng-ai 07609ef9c6 chore: v0.1.33 2026-11-01 18:35:25 +08:00
l0ng-ai bf2427bd3a feat(java): selectable Java formatting profiles (#680)
Java formatting comes from jdtls' Eclipse formatter, whose defaults differ from the IntelliJ IDEA code style. Settings › Editor › Code Style › Java now offers a formatting profile: Default (unchanged), IntelliJ IDEA, or a custom Eclipse formatter XML (absolute or project-relative path).

The IntelliJ IDEA profile is a bundled Eclipse formatter XML that follows IDEA's default Java code style item by item (indents, aligned multi-line parameters, annotation placement, else/catch/finally on the same line, array initializers, lambdas, blank lines, comments not reflowed). Manual line breaks are kept; lines longer than 120 columns wrap where necessary, which differs from IDEA's default of not wrapping. The profile reaches a running jdtls through didChangeConfiguration without a restart; an unreadable custom file shows a warning and leaves code intelligence running. Code style changes reconfigure language servers without scheduling Kotlin bridge builds.

Also drops two catalog entries whose texts are no longer used.

Fixes #649
2026-11-01 18:26:24 +08:00
l0ng-ai a3fb14fa86 fix(java): align debug JVM encoding with Run 2026-11-01 17:10:34 +08:00
7 changed files with 115 additions and 71 deletions

No files matched your search

Generated
+35 -35
View File
@@ -4038,7 +4038,7 @@ checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]] [[package]]
name = "ide-agent" name = "ide-agent"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"dunce", "dunce",
"encoding_rs", "encoding_rs",
@@ -4061,7 +4061,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-analysis" name = "ide-analysis"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ast-grep-core", "ast-grep-core",
"ide-core", "ide-core",
@@ -4075,7 +4075,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-build" name = "ide-build"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"dirs 6.0.0", "dirs 6.0.0",
"dunce", "dunce",
@@ -4090,7 +4090,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-clipboard" name = "ide-clipboard"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"objc2 0.6.5", "objc2 0.6.5",
"objc2-app-kit 0.3.2", "objc2-app-kit 0.3.2",
@@ -4099,7 +4099,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-core" name = "ide-core"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"dunce", "dunce",
"encoding_rs", "encoding_rs",
@@ -4115,7 +4115,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-coverage" name = "ide-coverage"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ide-core", "ide-core",
"ide-run", "ide-run",
@@ -4129,7 +4129,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-dap" name = "ide-dap"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ide-core", "ide-core",
"ide-jsonrpc", "ide-jsonrpc",
@@ -4147,7 +4147,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-db" name = "ide-db"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"bb8", "bb8",
"dirs 6.0.0", "dirs 6.0.0",
@@ -4169,7 +4169,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-docker" name = "ide-docker"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ide-core", "ide-core",
"libc", "libc",
@@ -4183,7 +4183,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-fonts" name = "ide-fonts"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"objc2-core-foundation", "objc2-core-foundation",
"objc2-core-text", "objc2-core-text",
@@ -4195,7 +4195,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-github" name = "ide-github"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ide-core", "ide-core",
"ide-vcs", "ide-vcs",
@@ -4209,7 +4209,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-host" name = "ide-host"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"dirs 6.0.0", "dirs 6.0.0",
"dunce", "dunce",
@@ -4254,7 +4254,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-http" name = "ide-http"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ide-core", "ide-core",
"parking_lot", "parking_lot",
@@ -4272,7 +4272,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-index" name = "ide-index"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"blake3", "blake3",
"criterion", "criterion",
@@ -4294,7 +4294,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-jsonrpc" name = "ide-jsonrpc"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"encoding_rs", "encoding_rs",
"futures", "futures",
@@ -4310,7 +4310,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-language" name = "ide-language"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"blake3", "blake3",
"criterion", "criterion",
@@ -4365,7 +4365,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-lsp" name = "ide-lsp"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"dunce", "dunce",
"futures", "futures",
@@ -4390,7 +4390,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-notebook" name = "ide-notebook"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"futures", "futures",
"ide-core", "ide-core",
@@ -4413,7 +4413,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-plugin" name = "ide-plugin"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ide-core", "ide-core",
"ide-language", "ide-language",
@@ -4431,7 +4431,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-profiler" name = "ide-profiler"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ide-core", "ide-core",
"ide-run", "ide-run",
@@ -4444,7 +4444,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-remote" name = "ide-remote"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"globset", "globset",
"ide-core", "ide-core",
@@ -4461,7 +4461,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-run" name = "ide-run"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"dunce", "dunce",
"encoding_rs", "encoding_rs",
@@ -4484,7 +4484,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-sdk" name = "ide-sdk"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"dunce", "dunce",
"ide-core", "ide-core",
@@ -4503,7 +4503,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-search" name = "ide-search"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"criterion", "criterion",
"globset", "globset",
@@ -4523,7 +4523,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-spell" name = "ide-spell"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ide-core", "ide-core",
"parking_lot", "parking_lot",
@@ -4536,7 +4536,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-ssh" name = "ide-ssh"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"dirs 6.0.0", "dirs 6.0.0",
"flate2", "flate2",
@@ -4555,7 +4555,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-syntax" name = "ide-syntax"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ide-core", "ide-core",
"ide-language", "ide-language",
@@ -4570,7 +4570,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-terminal" name = "ide-terminal"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ide-core", "ide-core",
"libc", "libc",
@@ -4583,7 +4583,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-text" name = "ide-text"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"criterion", "criterion",
"ide-core", "ide-core",
@@ -4595,7 +4595,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-tools" name = "ide-tools"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"flate2", "flate2",
"hex", "hex",
@@ -4616,7 +4616,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-vcs" name = "ide-vcs"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"dunce", "dunce",
"encoding_rs", "encoding_rs",
@@ -4635,7 +4635,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-vfs" name = "ide-vfs"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"chardetng", "chardetng",
"dunce", "dunce",
@@ -4657,7 +4657,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-web" name = "ide-web"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"ide-core", "ide-core",
"open", "open",
@@ -4673,7 +4673,7 @@ dependencies = [
[[package]] [[package]]
name = "ide-workspace" name = "ide-workspace"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"blake3", "blake3",
"dunce", "dunce",
@@ -6144,7 +6144,7 @@ dependencies = [
[[package]] [[package]]
name = "openidea" name = "openidea"
version = "0.1.32" version = "0.1.33"
dependencies = [ dependencies = [
"blake3", "blake3",
"block2 0.6.2", "block2 0.6.2",
+1 -1
View File
@@ -3,7 +3,7 @@ resolver = "3"
members = ["crates/*", "src-tauri"] members = ["crates/*", "src-tauri"]
[workspace.package] [workspace.package]
version = "0.1.32" version = "0.1.33"
edition = "2024" edition = "2024"
rust-version = "1.96" rust-version = "1.96"
license = "Apache-2.0" license = "Apache-2.0"
-20
View File
@@ -14,8 +14,6 @@
 ·   · 
<a href="#benchmark">Benchmark</a> <a href="#benchmark">Benchmark</a>
&nbsp;·&nbsp; &nbsp;·&nbsp;
<a href="#build">Build</a>
&nbsp;·&nbsp;
<a href="https://discord.gg/2Zy4yn7gP">Discord</a> <a href="https://discord.gg/2Zy4yn7gP">Discord</a>
</p> </p>
@@ -47,24 +45,6 @@ IDEA analyses Python more deeply, so "ready" doesn't mean the same work on
both sides. Both are measured from the outside, the same way: see both sides. Both are measured from the outside, the same way: see
[`perf/compare`](perf/compare) to run it on your machine and projects. [`perf/compare`](perf/compare) to run it on your machine and projects.
## Build
```sh
pnpm install
pnpm tauri dev
```
Rust 1.96, Node 22, pnpm and the [Tauri prerequisites](https://v2.tauri.app/start/prerequisites/).
Native notebook execution tests are opt-in and need two distinct Python environments
with `ipykernel` installed:
```sh
OPENIDEA_TEST_PYTHON=/first/env/bin/python \
OPENIDEA_TEST_PYTHON_SECOND=/second/env/bin/python \
cargo test -p ide-notebook --test kernel_runtime -- --ignored --test-threads=1
```
## License ## License
[Apache 2.0](LICENSE). Bundled third-party assets are listed in [`THIRD_PARTY_LICENSES.md`](THIRD_PARTY_LICENSES.md). [Apache 2.0](LICENSE). Bundled third-party assets are listed in [`THIRD_PARTY_LICENSES.md`](THIRD_PARTY_LICENSES.md).
+59 -10
View File
@@ -215,13 +215,21 @@ fn fix_kind(
} }
/// `vmArgs` of a launch by java-debug, which decodes the JVM's output as `encoding` /// `vmArgs` of a launch by java-debug, which decodes the JVM's output as `encoding`
/// (its launch attribute, UTF-8 when unset) and sets `file.encoding` itself. /// (its launch attribute, UTF-8 when unset). java-debug sets `file.encoding` only
pub fn java_debug_vm_args(vm_args: &str, encoding: Option<&str>, windows: bool) -> Option<String> { /// when that attribute is nonblank; use the same defaults and user overrides as [`fix`].
pub fn java_debug_vm_args(
vm_args: &str,
vars: &BTreeMap<String, String>,
inherited: impl Fn(&str) -> Option<String>,
encoding: Option<&str>,
windows: bool,
) -> Option<String> {
let encoding = encoding.map(str::trim).filter(|e| !e.is_empty()).unwrap_or("UTF-8"); let encoding = encoding.map(str::trim).filter(|e| !e.is_empty()).unwrap_or("UTF-8");
if (!windows && is_utf8(encoding)) || sets(vm_args, STD_PROPERTIES) { let added = fix_kind(Kind::Java, Some(&[vm_args.to_owned()]), vars, inherited, encoding, windows).java_args;
if added.is_empty() {
return None; return None;
} }
let added = options(STD_PROPERTIES, encoding).join(" "); let added = added.join(" ");
Some(match vm_args.trim() { Some(match vm_args.trim() {
"" => added, "" => added,
own => format!("{own} {added}"), own => format!("{own} {added}"),
@@ -446,12 +454,53 @@ mod tests {
#[test] #[test]
fn java_debug_launches_write_what_java_debug_decodes() { fn java_debug_launches_write_what_java_debug_decodes() {
assert_eq!(java_debug_vm_args("", None, true).as_deref(), Some(TOOL_UTF8)); let debug =
assert_eq!(java_debug_vm_args("-Xmx1g", Some(""), true), Some(format!("-Xmx1g {TOOL_UTF8}"))); |args: &str, encoding, windows| java_debug_vm_args(args, &BTreeMap::new(), |_| None, encoding, windows);
assert_eq!(java_debug_vm_args("", Some("GBK"), true).unwrap().split(' ').next(), Some("-Dstdout.encoding=GBK")); for encoding in [None, Some(""), Some(" "), Some("UTF-8"), Some("utf8")] {
assert_eq!(java_debug_vm_args("-Dstdout.encoding=GBK", None, true), None); let streams = encoding.filter(|e| !e.trim().is_empty()).unwrap_or("UTF-8");
assert_eq!(java_debug_vm_args("-Xmx1g", None, false), None); let utf8 = format!("{} -Dfile.encoding=UTF-8", options(STD_PROPERTIES, streams).join(" "));
assert!(java_debug_vm_args("", Some("GBK"), false).is_some()); assert_eq!(debug("", encoding, true), Some(utf8.clone()));
assert_eq!(debug("-Xmx1g", encoding, true), Some(format!("-Xmx1g {utf8}")));
assert_eq!(debug("-Xmx1g", encoding, false), None);
}
for windows in [true, false] {
assert_eq!(debug("", Some("GBK"), windows), Some(options(STD_PROPERTIES, "GBK").join(" ")));
}
}
#[test]
fn java_debug_preserves_user_options_independently() {
let debug = |args: &str| java_debug_vm_args(args, &BTreeMap::new(), |_| None, None, true);
assert_eq!(debug("-Dfile.encoding=GBK"), Some(format!("-Dfile.encoding=GBK {TOOL_UTF8}")));
for property in STD_PROPERTIES {
let args = format!("-D{property}=GBK");
assert_eq!(debug(&args), Some(format!("{args} -Dfile.encoding=UTF-8")));
assert_eq!(debug(&format!("{args} -Dfile.encoding=GBK")), None);
}
for key in ["JDK_JAVA_OPTIONS", TOOL_OPTIONS] {
for (own, expected) in [
("-Dfile.encoding=GBK", Some(TOOL_UTF8.to_owned())),
("-Dstdout.encoding=GBK", Some("-Dfile.encoding=UTF-8".to_owned())),
("-Dstdout.encoding=GBK -Dfile.encoding=GBK", None),
] {
assert_eq!(java_debug_vm_args("", &vars(&[(key, own)]), |_| None, None, true), expected);
assert_eq!(
java_debug_vm_args("", &BTreeMap::new(), |k| (k == key).then(|| own.to_owned()), None, true),
expected
);
}
// A launch environment value overrides the inherited one, as in Run.
assert_eq!(
java_debug_vm_args(
"",
&vars(&[(key, "")]),
|k| (k == key).then(|| "-Dfile.encoding=GBK".into()),
None,
true
),
Some(format!("{TOOL_UTF8} -Dfile.encoding=UTF-8"))
);
}
} }
fn filtered(chunks: &[&str]) -> String { fn filtered(chunks: &[&str]) -> String {
+18 -3
View File
@@ -96,7 +96,13 @@ fn match_java_debug_encoding(mut config: LaunchConfig, windows: bool) -> LaunchC
}; };
let vm_args = extra.get("vmArgs").and_then(|v| v.as_str()).unwrap_or_default(); let vm_args = extra.get("vmArgs").and_then(|v| v.as_str()).unwrap_or_default();
let encoding = extra.get("encoding").and_then(|v| v.as_str()); let encoding = extra.get("encoding").and_then(|v| v.as_str());
if let Some(vm_args) = ide_core::output_encoding::java_debug_vm_args(vm_args, encoding, windows) { if let Some(vm_args) = ide_core::output_encoding::java_debug_vm_args(
vm_args,
&config.env,
|key| std::env::var(key).ok(),
encoding,
windows,
) {
extra.insert("vmArgs".into(), vm_args.into()); extra.insert("vmArgs".into(), vm_args.into());
config.extra_json = Some(serde_json::Value::Object(extra).to_string()); config.extra_json = Some(serde_json::Value::Object(extra).to_string());
} }
@@ -452,7 +458,7 @@ mod tests {
program: None, program: None,
args: vec![], args: vec![],
cwd: None, cwd: None,
env: Default::default(), env: [("JDK_JAVA_OPTIONS".into(), "".into()), ("JAVA_TOOL_OPTIONS".into(), "".into())].into(),
extra_json: Some(extra.to_string()), extra_json: Some(extra.to_string()),
} }
} }
@@ -468,7 +474,7 @@ mod tests {
let fixed = match_java_debug_encoding(launch("java-debug", "launch", extra.clone()), true); let fixed = match_java_debug_encoding(launch("java-debug", "launch", extra.clone()), true);
assert_eq!( assert_eq!(
vm_args(&fixed), vm_args(&fixed),
"-Xmx1g -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8" "-Xmx1g -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -Dfile.encoding=UTF-8"
); );
assert_eq!( assert_eq!(
serde_json::from_str::<serde_json::Value>(fixed.extra_json.as_deref().unwrap()).unwrap()["mainClass"], serde_json::from_str::<serde_json::Value>(fixed.extra_json.as_deref().unwrap()).unwrap()["mainClass"],
@@ -481,4 +487,13 @@ mod tests {
assert_eq!(vm_args(&match_java_debug_encoding(launch(adapter, request, extra.clone()), windows)), "-Xmx1g"); assert_eq!(vm_args(&match_java_debug_encoding(launch(adapter, request, extra.clone()), windows)), "-Xmx1g");
} }
} }
#[test]
fn java_debug_launches_respect_environment_encoding() {
for key in ["JDK_JAVA_OPTIONS", "JAVA_TOOL_OPTIONS"] {
let mut config = launch("java-debug", "launch", serde_json::json!({"vmArgs": "-Dstdout.encoding=GBK"}));
config.env.insert(key.into(), "-Dfile.encoding=GBK".into());
assert_eq!(vm_args(&match_java_debug_encoding(config, true)), "-Dstdout.encoding=GBK");
}
}
} }
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "openidea", "name": "openidea",
"private": true, "private": true,
"description": "An open-source IDE inspired by IntelliJ IDEA", "description": "An open-source IDE inspired by IntelliJ IDEA",
"version": "0.1.32", "version": "0.1.33",
"license": "Apache-2.0", "license": "Apache-2.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "OpenIDEA", "productName": "OpenIDEA",
"version": "0.1.32", "version": "0.1.33",
"identifier": "ai.l0ng.openidea", "identifier": "ai.l0ng.openidea",
"build": { "build": {
"beforeDevCommand": "pnpm dev", "beforeDevCommand": "pnpm dev",