Skip to content

Commit c0feac2

Browse files
Faizanqseemeroland
andauthored
Expand ~ in warp://action/new_tab?path= URLs (#9277)
## Description Fixes #9178. `warp://action/new_tab?path=~/foo` was opening the current directory instead of `~/foo`. The query value was being passed straight into `PathBuf::from_str`, which doesn't expand `~`, so the resulting literal `~/foo` couldn't be resolved by `open_file` and the new tab silently fell back to the current location. Routed the `path` query through `shellexpand::tilde` (already a workspace dependency) before constructing the `PathBuf`. The same call site serves both `/new_tab` and `/new_window`, so both URLs benefit. Absolute and relative paths are unchanged. ## Testing Added 6 unit tests in `app/src/uri/uri_test.rs`: - `~/Projects` expands to `$HOME/Projects` - URL-encoded `%7E%2FProjects` expands the same way - absolute path `/tmp/foo` unchanged - relative path `relative/dir` unchanged - missing `path=` returns `None` - bare `~` expands to `$HOME` Also verified the helper in a standalone harness against extra edge cases: empty value, non-leading `~` (unchanged, correct shell semantics), `~user/path` (unchanged, a shellexpand limitation), and URL-encoded spaces. Couldn't run the in-tree test suite locally because the Metal toolchain isn't installed, so relying on CI for the full clippy / nextest pass. ## Agent Mode - [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode ## Changelog Entries for Stable CHANGELOG-BUG-FIX: `warp://action/new_tab?path=~/foo` (and `/new_window`) now expand `~` to your home directory. --------- Co-authored-by: seemeroland <roland@warp.dev>
1 parent 389716a commit c0feac2

2 files changed

Lines changed: 48 additions & 5 deletions

File tree

app/src/uri/mod.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,13 @@ fn find_matching_config_name<'a>(
657657
.find(|&config| config.name.to_lowercase() == target_name_lower)
658658
}
659659

660+
/// Extract the `path` query parameter, expanding a leading `~` to the
661+
/// user's home directory.
662+
fn parse_tab_path(url: &Url) -> Option<PathBuf> {
663+
let raw = url.query_pairs().find(|(k, _)| k == "path")?.1;
664+
Some(PathBuf::from(shellexpand::tilde(&raw).into_owned()))
665+
}
666+
660667
#[derive(Debug)]
661668
enum Action {
662669
NewTab,
@@ -706,11 +713,7 @@ impl Action {
706713
} else {
707714
None
708715
};
709-
let Some(Ok(path)) = url
710-
.query_pairs()
711-
.find(|(k, _v)| k == "path")
712-
.map(|(_, path)| PathBuf::from_str(&path))
713-
else {
716+
let Some(path) = parse_tab_path(url) else {
714717
log::warn!("Could not parse path to open a new tab/window");
715718
return;
716719
};

app/src/uri/uri_test.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,3 +533,43 @@ fn validate_custom_uri_errors_do_not_leak_query_string() {
533533
assert!(!msg.contains("refresh_token"), "{msg}");
534534
assert!(!msg.contains("LEAKED"), "{msg}");
535535
}
536+
537+
#[test]
538+
fn test_parse_tab_path_expands_tilde() {
539+
let url = Url::parse("warp://action/new_tab?path=~/Projects").unwrap();
540+
let home = dirs::home_dir().expect("HOME must be set for this test");
541+
assert_eq!(parse_tab_path(&url), Some(home.join("Projects")));
542+
}
543+
544+
#[test]
545+
fn test_parse_tab_path_expands_url_encoded_tilde() {
546+
// `%7E` and `%2F` are URL-encoded `~` and `/`.
547+
let url = Url::parse("warp://action/new_tab?path=%7E%2FProjects").unwrap();
548+
let home = dirs::home_dir().expect("HOME must be set for this test");
549+
assert_eq!(parse_tab_path(&url), Some(home.join("Projects")));
550+
}
551+
552+
#[test]
553+
fn test_parse_tab_path_absolute_path_unchanged() {
554+
let url = Url::parse("warp://action/new_tab?path=/tmp/foo").unwrap();
555+
assert_eq!(parse_tab_path(&url), Some(PathBuf::from("/tmp/foo")));
556+
}
557+
558+
#[test]
559+
fn test_parse_tab_path_relative_path_unchanged() {
560+
let url = Url::parse("warp://action/new_tab?path=relative/dir").unwrap();
561+
assert_eq!(parse_tab_path(&url), Some(PathBuf::from("relative/dir")));
562+
}
563+
564+
#[test]
565+
fn test_parse_tab_path_missing_returns_none() {
566+
let url = Url::parse("warp://action/new_tab").unwrap();
567+
assert_eq!(parse_tab_path(&url), None);
568+
}
569+
570+
#[test]
571+
fn test_parse_tab_path_bare_tilde() {
572+
let url = Url::parse("warp://action/new_tab?path=~").unwrap();
573+
let home = dirs::home_dir().expect("HOME must be set for this test");
574+
assert_eq!(parse_tab_path(&url), Some(home));
575+
}

0 commit comments

Comments
 (0)