1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//! IDE path conversion utilities
//!
//! Handles conversions between Claude's environment and the IDE's environment.
use std::process::Command;
/// Path converter trait for IDE communication
pub trait IdePathConverter {
/// Convert path from IDE format to local format
fn to_local_path(&self, ide_path: &str) -> String;
/// Convert path from local format to IDE format
fn to_ide_path(&self, local_path: &str) -> String;
}
/// Converter for Windows IDE + WSL Claude scenario
pub struct WindowsToWSLConverter {
wsl_distro_name: Option<String>,
}
impl WindowsToWSLConverter {
/// Create a new converter
pub fn new(wsl_distro_name: Option<String>) -> Self {
Self { wsl_distro_name }
}
}
impl IdePathConverter for WindowsToWSLConverter {
fn to_local_path(&self, windows_path: &str) -> String {
if windows_path.is_empty() {
return windows_path.to_string();
}
// Check if this is a path from a different WSL distro
if let Some(ref distro) = self.wsl_distro_name {
if let Some(caps) = regex::Regex::new(r"^\\\\wsl(?:\.localhost|\$)\\([^\\]+)(.*)$")
.ok()
.and_then(|r| r.captures(windows_path))
{
if caps.get(1).map(|m| m.as_str()) != Some(distro.as_str()) {
// Different distro - wslpath will fail, so return original path
return windows_path.to_string();
}
}
}
// Try wslpath first
if let Ok(result) = Command::new("wslpath").args(["-u", windows_path]).output() {
if result.status.success() {
return String::from_utf8_lossy(&result.stdout).trim().to_string();
}
}
// Fall back to manual conversion
// Convert backslashes to forward slashes
let result = windows_path.replace('\\', "/");
// Convert drive letter (e.g., C: -> /mnt/c)
if result.len() >= 2 && result.chars().nth(1) == Some(':') {
let letter = result.chars().next().unwrap().to_ascii_lowercase();
return format!("/mnt/{}{}", letter, &result[2..]);
}
result
}
fn to_ide_path(&self, wsl_path: &str) -> String {
if wsl_path.is_empty() {
return wsl_path.to_string();
}
// Try wslpath first
if let Ok(result) = Command::new("wslpath").args(["-w", wsl_path]).output() {
if result.status.success() {
return String::from_utf8_lossy(&result.stdout).trim().to_string();
}
}
// If wslpath fails, return the original path
wsl_path.to_string()
}
}
/// Check if distro names match for WSL UNC paths
///
/// # Arguments
/// * `windows_path` - The Windows path to check
/// * `wsl_distro_name` - The WSL distro name to match against
///
/// # Returns
/// True if the path matches the distro or is not a WSL UNC path
pub fn check_wsl_distro_match(windows_path: &str, wsl_distro_name: &str) -> bool {
if let Some(caps) = regex::Regex::new(r"^\\\\wsl(?:\.localhost|\$)\\([^\\]+)(.*)$")
.ok()
.and_then(|r| r.captures(windows_path))
{
caps.get(1).map(|m| m.as_str()) == Some(wsl_distro_name)
} else {
true // Not a WSL UNC path, so no distro mismatch
}
}