first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
+59 -19
View File
@@ -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());
}