diff --git a/crates/ide-host/src/data_dirs.rs b/crates/ide-host/src/data_dirs.rs index 4164212f7..9c96c4153 100644 --- a/crates/ide-host/src/data_dirs.rs +++ b/crates/ide-host/src/data_dirs.rs @@ -244,7 +244,7 @@ fn relocate_shims(root: &Path, source: &Path) -> io::Result<()> { } let text = fs::read_to_string(&path)?; if text.starts_with("@echo off\r\n") { - let updated = text.replace(source.to_string_lossy().as_ref(), "%~dp0.."); + let updated = relative_wrapper(&text, source); if updated != text { fs::write(path, updated)?; } @@ -253,10 +253,37 @@ fn relocate_shims(root: &Path, source: &Path) -> io::Result<()> { Ok(()) } +fn relative_wrapper(text: &str, source: &Path) -> String { + // PathBuf can contain both separators (notably roots joined with "tools/demo"). + // Compare normalized paths, but retain every other byte of the managed wrapper. + let normalized = text.replace('\\', "/"); + let prefix = source.to_string_lossy().replace('\\', "/"); + #[cfg(windows)] + let (normalized, prefix) = (normalized.to_ascii_lowercase(), prefix.to_ascii_lowercase()); + let mut updated = text.to_owned(); + let offsets: Vec<_> = normalized.match_indices(&prefix).map(|(offset, _)| offset).collect(); + for offset in offsets.into_iter().rev() { + let end = offset + prefix.len(); + if normalized.as_bytes().get(end) == Some(&b'/') { + updated.replace_range(offset..end, "%~dp0.."); + } + } + updated +} + #[cfg(test)] mod tests { use super::*; + #[test] + fn wrappers_accept_mixed_separators_without_rewriting_neighbor_paths() { + let text = "@echo off\r\n\"C:\\old\\tools/demo\\payload.exe\" \"C:\\old\\tools/demo-other\\x\" %*\r\n"; + assert_eq!( + relative_wrapper(text, Path::new("C:/old/tools/demo")), + "@echo off\r\n\"%~dp0..\\payload.exe\" \"C:\\old\\tools/demo-other\\x\" %*\r\n" + ); + } + #[test] fn storage_policy_is_conservative_and_preserves_unix_layout() { for entry in [ diff --git a/crates/ide-host/src/formatter.rs b/crates/ide-host/src/formatter.rs index 2da08e368..7bc9af9d1 100644 --- a/crates/ide-host/src/formatter.rs +++ b/crates/ide-host/src/formatter.rs @@ -45,7 +45,7 @@ pub async fn format( } let config = config.unwrap().clone(); let custom = ide_sdk::apply::setting_path(&project.root, &prettier.path); - let tools = Tools::new(&host.data_dir); + let tools = Tools::new(&host.local_data_dir); let whole_selection = range.is_some() && !config.range; let edits: IdeResult> = tokio::task::spawn_blocking(move || { let text = ide_text::Document::new(&snap.text); diff --git a/crates/ide-host/src/ops/tools.rs b/crates/ide-host/src/ops/tools.rs index edeae318c..b92399c2f 100644 --- a/crates/ide-host/src/ops/tools.rs +++ b/crates/ide-host/src/ops/tools.rs @@ -104,7 +104,7 @@ pub async fn jdk_download_releases( vendor: String, request: RequestId, ) -> IdeResult { - let tools = Tools::new(&host.data_dir); + let tools = Tools::new(&host.local_data_dir); let cancel = host.begin_request(request); let result = tokio::task::spawn_blocking(move || tools.jdk_releases(&vendor, &cancel)).await.map_err(join_err); host.end_request(request); @@ -130,7 +130,7 @@ pub async fn jdk_download( request: RequestId, on_event: Channel, ) -> IdeResult { - let tools = Tools::new(&host.data_dir); + let tools = Tools::new(&host.local_data_dir); let location = location.filter(|p| !p.as_os_str().is_empty()); let cancel = host.begin_request(request); let result = tokio::task::spawn_blocking(move || { diff --git a/crates/ide-host/src/project.rs b/crates/ide-host/src/project.rs index 7ac81aac1..faf28db01 100644 --- a/crates/ide-host/src/project.rs +++ b/crates/ide-host/src/project.rs @@ -255,8 +255,8 @@ impl Host { let kotlin_bridge = crate::kotlin_bridge::KotlinBridge::new( root.clone(), - self.data_dir.join("cache").join(&project_key).join("build"), - &self.data_dir, + self.local_data_dir.join("cache").join(&project_key).join("build"), + &self.local_data_dir, settings.clone(), lsp.clone(), sink.clone(),