diff --git a/src/config.rs b/src/config.rs index 9aa99e7..30cdbb3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -94,6 +94,24 @@ pub fn get_jdtls_launcher(configuration: &Option, worktree: &Worktree) -> None } +/// Returns the max heap size for jdtls (e.g. "2G", "4096m"). +/// Maps to the `-Xmx` JVM argument. +pub fn get_max_memory(configuration: &Option) -> Option { + configuration + .as_ref() + .and_then(|c| c.pointer("/max_memory").and_then(|v| v.as_str())) + .map(|s| s.to_string()) +} + +/// Returns the initial heap size for jdtls (e.g. "512m", "1G"). +/// Maps to the `-Xms` JVM argument. Defaults to "1G". +pub fn get_min_memory(configuration: &Option) -> Option { + configuration + .as_ref() + .and_then(|c| c.pointer("/min_memory").and_then(|v| v.as_str())) + .map(|s| s.to_string()) +} + pub fn get_lombok_jar(configuration: &Option, worktree: &Worktree) -> Option { if let Some(configuration) = configuration && let Some(jar_path) = configuration diff --git a/src/jdtls.rs b/src/jdtls.rs index 18972a1..5bcb23a 100644 --- a/src/jdtls.rs +++ b/src/jdtls.rs @@ -34,6 +34,18 @@ const LOMBOK_REPO: &str = "projectlombok/lombok"; const JAVA_VERSION_ERROR: &str = "JDTLS requires at least Java version 21 to run. You can either specify a different JDK to use by configuring lsp.jdtls.settings.java_home to point to a different JDK, or set lsp.jdtls.settings.jdk_auto_download to true to let the extension automatically download one for you."; const JDTLS_VERION_ERROR: &str = "No version to fallback to"; +/// Parse a JVM memory string (e.g. "2G", "512m", "1024k") into bytes. +fn parse_memory_value(s: &str) -> Option { + let s = s.trim(); + let (num, multiplier) = match s.as_bytes().last()? { + b'g' | b'G' => (&s[..s.len() - 1], 1024 * 1024 * 1024), + b'm' | b'M' => (&s[..s.len() - 1], 1024 * 1024), + b'k' | b'K' => (&s[..s.len() - 1], 1024), + _ => (s, 1), + }; + num.parse::().ok().map(|n| n * multiplier) +} + pub fn build_jdtls_launch_args( jdtls_path: &PathBuf, configuration: &Option, @@ -85,13 +97,30 @@ pub fn build_jdtls_launch_args( "-Dosgi.sharedConfiguration.area.readOnly=true".to_string(), "-Dosgi.configuration.cascaded=true".to_string(), "-Djava.import.generatesMetadataFilesAtProjectRoot=false".to_string(), - "-Xms1G".to_string(), + ]; + { + let mut min = + crate::config::get_min_memory(configuration).unwrap_or_else(|| "1G".to_string()); + let mut max = crate::config::get_max_memory(configuration); + if let Some(ref max_val) = max + && let (Some(min_bytes), Some(max_bytes)) = + (parse_memory_value(&min), parse_memory_value(max_val)) + && min_bytes > max_bytes + { + std::mem::swap(&mut min, max.as_mut().unwrap()); + } + args.push(format!("-Xms{min}")); + if let Some(max_val) = max { + args.push(format!("-Xmx{max_val}")); + } + } + args.extend(vec![ "--add-modules=ALL-SYSTEM".to_string(), "--add-opens".to_string(), "java.base/java.util=ALL-UNNAMED".to_string(), "--add-opens".to_string(), "java.base/java.lang=ALL-UNNAMED".to_string(), - ]; + ]); args.extend(jvm_args); args.extend(vec![ "-jar".to_string(),