Files
galaxy/crates/ai/src/paths.rs
T

126 lines
4.2 KiB
Rust

use galaxy_terminal::shell::ShellLaunchData;
use galaxy_util::path::{
convert_msys2_to_windows_native_path, convert_wsl_to_windows_host_path, msys2_exe_to_root,
};
use galaxyui::platform::OperatingSystem;
use typed_path::{TypedPath, TypedPathBuf, WindowsPath};
fn use_unix_paths(shell: Option<&ShellLaunchData>) -> bool {
OperatingSystem::get().is_linux()
|| OperatingSystem::get().is_mac()
|| shell.is_some_and(|shell| {
matches!(
shell,
ShellLaunchData::WSL { .. } | ShellLaunchData::MSYS2 { .. }
)
})
}
pub fn join_paths(paths: &[&str], shell: Option<&ShellLaunchData>) -> String {
let use_unix_paths = use_unix_paths(shell);
let base_path = if use_unix_paths {
TypedPathBuf::unix()
} else {
TypedPathBuf::windows()
};
paths
.iter()
.fold(base_path, |acc, path| acc.join(path))
.to_string_lossy()
.into_owned()
}
fn shell_native_absolute_path_internal(
file_path: &str,
shell: Option<&ShellLaunchData>,
current_working_directory: &str,
) -> TypedPathBuf {
let expanded_path = shellexpand::tilde(file_path).into_owned();
let use_unix_paths = use_unix_paths(shell);
let (cwd, file_path) = if use_unix_paths {
(
TypedPathBuf::from_unix(current_working_directory),
TypedPath::unix(&expanded_path),
)
} else {
(
TypedPathBuf::from_windows(current_working_directory),
TypedPath::windows(&expanded_path),
)
};
cwd.join(file_path).normalize()
}
/// Returns the absolute path of the path in the shell's native format.
///
/// On Unix systems, this will always be Unix encoded paths. On Windows, this
/// will be a Windows encoded path unless the user is using WSL or Git Bash, in
/// which case Unix encoded paths will be used.
pub fn shell_native_absolute_path(
file_path: &str,
shell: Option<&ShellLaunchData>,
current_working_directory: Option<&String>,
) -> String {
let Some(cwd) = current_working_directory else {
return shellexpand::tilde(file_path).into_owned();
};
shell_native_absolute_path_internal(file_path, shell, cwd)
.to_string_lossy()
.into_owned()
}
/// Returns the absolute path of the path in the host's native format.
///
/// This should be used over [`shell_native_absolute_path`] when we need an
/// absolute path in the format of the user's OS, regardless of what shell
/// they're using. e.g. A Windows encoded path when the user is using WSL.
pub fn host_native_absolute_path(
file_path: &str,
shell: &Option<ShellLaunchData>,
current_working_directory: &Option<String>,
) -> String {
let Some(cwd) = current_working_directory.as_ref() else {
return shellexpand::tilde(file_path).into_owned();
};
let normalized_path = shell_native_absolute_path_internal(file_path, shell.as_ref(), cwd);
match shell {
Some(ShellLaunchData::WSL { distro }) => {
match convert_wsl_to_windows_host_path(&normalized_path.to_path(), distro) {
Ok(path) => path.to_string_lossy().into_owned(),
Err(err) => {
log::error!(
"Could not convert WSL to Windows host path {normalized_path:?}: {err:#}"
);
normalized_path.to_string_lossy().into_owned()
}
}
}
Some(ShellLaunchData::MSYS2 {
executable_path, ..
}) => {
match convert_msys2_to_windows_native_path(
&normalized_path.to_path(),
&msys2_exe_to_root(WindowsPath::new(
executable_path.as_os_str().as_encoded_bytes(),
)),
) {
Ok(path) => path.to_string_lossy().into_owned(),
Err(err) => {
log::error!(
"Could not convert MSYS2 to Windows host path {normalized_path:?}: {err:#}"
);
normalized_path.to_string_lossy().into_owned()
}
}
}
_ => normalized_path.to_string_lossy().into_owned(),
}
}
#[cfg(test)]
#[path = "paths_tests.rs"]
mod tests;