first pass of merging in warp (doesn't build)
This commit is contained in:
@@ -21,9 +21,8 @@ use smol_str::SmolStr;
|
||||
use typed_path::{TypedPath, TypedPathBuf, WindowsPath};
|
||||
use version_compare::{Cmp, Version};
|
||||
|
||||
use crate::model::escape_sequences;
|
||||
|
||||
use self::unescape::unescape_quotes;
|
||||
use crate::model::escape_sequences;
|
||||
|
||||
const ZSH_META: u8 = 0x83;
|
||||
|
||||
@@ -333,31 +332,44 @@ impl ShellType {
|
||||
}
|
||||
|
||||
/// Returns the potential paths to the RC file relative to the `home` directory.
|
||||
pub fn rc_file_paths(&self, os: TargetOS) -> Vec<PathBuf> {
|
||||
let home_dir = Path::new(match os {
|
||||
TargetOS::Windows => "$HOME",
|
||||
_ => "~",
|
||||
});
|
||||
let relative_paths = match (self, os) {
|
||||
///
|
||||
/// The returned [`TypedPathBuf`]s are encoded for the target OS rather than the
|
||||
/// host OS, because the resulting path is rendered into a shell command executed
|
||||
/// on the target (e.g. via SSH or Auto-Warpify). A plain `PathBuf` would pick the
|
||||
/// host's separator and produce strings like `~\.zshrc` on a Windows host when
|
||||
/// targeting a Unix shell, which the remote shell cannot resolve. Encoding for
|
||||
/// the target OS lets `TypedPathBuf` enforce the correct separator.
|
||||
pub fn rc_file_paths(&self, os: TargetOS) -> Vec<TypedPathBuf> {
|
||||
let is_windows = matches!(os, TargetOS::Windows);
|
||||
let home_dir = if is_windows { "$HOME" } else { "~" };
|
||||
let relative_paths: Vec<&str> = match (self, os) {
|
||||
(ShellType::PowerShell, TargetOS::Windows) => {
|
||||
vec![Path::new(
|
||||
".config/powershell/Microsoft.PowerShell_profile.ps1",
|
||||
)]
|
||||
vec![".config/powershell/Microsoft.PowerShell_profile.ps1"]
|
||||
}
|
||||
// We need to make sure this works for either editor of PowerShell (PowerShell Core or
|
||||
// Windows PowerShell) so just write the file to both.
|
||||
(ShellType::PowerShell, _) => vec![
|
||||
Path::new("Documents/PowerShell/Microsoft.PowerShell_profile.ps1"),
|
||||
Path::new("Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1"),
|
||||
"Documents/PowerShell/Microsoft.PowerShell_profile.ps1",
|
||||
"Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1",
|
||||
],
|
||||
(_, TargetOS::Windows) => vec![],
|
||||
(ShellType::Bash, _) => vec![Path::new(".bashrc")],
|
||||
(ShellType::Zsh, _) => vec![Path::new(".zshrc")],
|
||||
(ShellType::Fish, _) => vec![Path::new(".config/fish/config.fish")],
|
||||
(ShellType::Bash, _) => vec![".bashrc"],
|
||||
(ShellType::Zsh, _) => vec![".zshrc"],
|
||||
(ShellType::Fish, _) => vec![".config/fish/config.fish"],
|
||||
};
|
||||
relative_paths
|
||||
.iter()
|
||||
.map(|relative_path| home_dir.join(relative_path))
|
||||
.map(|relative_path| {
|
||||
let mut path = if is_windows {
|
||||
TypedPathBuf::from_windows(home_dir)
|
||||
} else {
|
||||
TypedPathBuf::from_unix(home_dir)
|
||||
};
|
||||
// `push` uses the separator of the encoding picked above, so the
|
||||
// result follows the target OS regardless of the host.
|
||||
path.push(relative_path);
|
||||
path
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -519,7 +531,7 @@ impl ShellType {
|
||||
|
||||
ShellType::Fish => {
|
||||
let history_file_contents = String::from_utf8_lossy(history_file_bytes);
|
||||
// fish has psuedo-yaml.
|
||||
// fish has pseudo-yaml.
|
||||
// The commands start with "- cmd: ".
|
||||
history_lines = history_file_contents
|
||||
.lines()
|
||||
@@ -619,7 +631,10 @@ impl ShellType {
|
||||
// this will print one item per line. However, when it is converted to a string,
|
||||
// it will join the entries together with a space. So to make sure we get one item
|
||||
// per line, we explicitly join the results with a newline.
|
||||
"Get-Command -CommandType Application | Select-Object -ExpandProperty Name"
|
||||
//
|
||||
// We write the joined text to stdout as explicit UTF-8 bytes so localized
|
||||
// executable names do not depend on the machine's active Windows code page.
|
||||
r#"$names = Get-Command -CommandType Application | Select-Object -ExpandProperty Name; $text = [string]::Join([Environment]::NewLine, $names); $bytes = [System.Text.UTF8Encoding]::new($false).GetBytes($text); [Console]::OpenStandardOutput().Write($bytes, 0, $bytes.Length)"#
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -725,6 +740,31 @@ impl ShellType {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shell_command_to_get_all_functions(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
ShellType::PowerShell => Some(
|
||||
"$names = Get-Command -CommandType Function | Where-Object { \
|
||||
-not $_.Name.StartsWith('Warp') } | Select-Object -ExpandProperty Name; \
|
||||
$text = [string]::Join([Environment]::NewLine, $names); \
|
||||
$bytes = [System.Text.UTF8Encoding]::new($false).GetBytes($text); \
|
||||
[Console]::OpenStandardOutput().Write($bytes, 0, $bytes.Length)",
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shell_command_to_get_all_builtins(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
ShellType::PowerShell => Some(
|
||||
"$names = Get-Command -CommandType Cmdlet | Select-Object -ExpandProperty Name; \
|
||||
$text = [string]::Join([Environment]::NewLine, $names); \
|
||||
$bytes = [System.Text.UTF8Encoding]::new($false).GetBytes($text); \
|
||||
[Console]::OpenStandardOutput().Write($bytes, 0, $bytes.Length)",
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn force_in_band_command_executor(&self) -> bool {
|
||||
// TODO: Remove this function once we have confidence in using a local executor in
|
||||
// powershell.
|
||||
|
||||
@@ -270,3 +270,55 @@ fn test_should_add_command_to_history() {
|
||||
assert!(fish_shell.should_add_command_to_history(" asdf"));
|
||||
}
|
||||
}
|
||||
|
||||
/// Regression test for https://github.com/warpdotdev/warp/issues/10474.
|
||||
///
|
||||
/// `rc_file_paths` is rendered into a shell command that runs on the *target*
|
||||
/// (e.g. an SSH remote, or a subshell during Auto-Warpify). The path separator
|
||||
/// must therefore depend on the target OS, not the host that built Warp.
|
||||
/// Previously this used `PathBuf::join`, which uses the host's separator and
|
||||
/// produced strings like `~\.zshrc` on a Windows host targeting a Unix shell —
|
||||
/// the remote zsh then errored with "no such user or named directory".
|
||||
/// `rc_file_paths` now returns `TypedPathBuf`s encoded for the target OS, so the
|
||||
/// separator is enforced by the encoding rather than the host.
|
||||
#[test]
|
||||
fn test_rc_file_paths_use_target_os_separator() {
|
||||
for os in [TargetOS::Linux, TargetOS::MacOS] {
|
||||
assert_eq!(
|
||||
ShellType::Zsh.rc_file_paths(os.clone()),
|
||||
vec![TypedPathBuf::from_unix("~/.zshrc")],
|
||||
"Zsh rc path on {os:?} should use forward slash regardless of host",
|
||||
);
|
||||
assert_eq!(
|
||||
ShellType::Bash.rc_file_paths(os.clone()),
|
||||
vec![TypedPathBuf::from_unix("~/.bashrc")],
|
||||
);
|
||||
assert_eq!(
|
||||
ShellType::Fish.rc_file_paths(os.clone()),
|
||||
vec![TypedPathBuf::from_unix("~/.config/fish/config.fish")],
|
||||
);
|
||||
assert_eq!(
|
||||
ShellType::PowerShell.rc_file_paths(os),
|
||||
vec![
|
||||
TypedPathBuf::from_unix("~/Documents/PowerShell/Microsoft.PowerShell_profile.ps1"),
|
||||
TypedPathBuf::from_unix(
|
||||
"~/Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1"
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// On Windows the only Auto-Warpify-supported shell is PowerShell; Unix
|
||||
// shells deliberately return no rc paths.
|
||||
// The leading separator follows target OS; the literal interior slashes
|
||||
// are left as-is (PowerShell accepts forward slashes on Windows).
|
||||
assert_eq!(
|
||||
ShellType::PowerShell.rc_file_paths(TargetOS::Windows),
|
||||
vec![TypedPathBuf::from_windows(
|
||||
"$HOME\\.config/powershell/Microsoft.PowerShell_profile.ps1"
|
||||
)],
|
||||
);
|
||||
assert!(ShellType::Zsh.rc_file_paths(TargetOS::Windows).is_empty());
|
||||
assert!(ShellType::Bash.rc_file_paths(TargetOS::Windows).is_empty());
|
||||
assert!(ShellType::Fish.rc_file_paths(TargetOS::Windows).is_empty());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user