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>
This commit is contained in:
co-authored by
seemeroland
parent
389716a905
commit
c0feac21db
+8
-5
@@ -657,6 +657,13 @@ fn find_matching_config_name<'a>(
|
|||||||
.find(|&config| config.name.to_lowercase() == target_name_lower)
|
.find(|&config| config.name.to_lowercase() == target_name_lower)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extract the `path` query parameter, expanding a leading `~` to the
|
||||||
|
/// user's home directory.
|
||||||
|
fn parse_tab_path(url: &Url) -> Option<PathBuf> {
|
||||||
|
let raw = url.query_pairs().find(|(k, _)| k == "path")?.1;
|
||||||
|
Some(PathBuf::from(shellexpand::tilde(&raw).into_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Action {
|
enum Action {
|
||||||
NewTab,
|
NewTab,
|
||||||
@@ -706,11 +713,7 @@ impl Action {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let Some(Ok(path)) = url
|
let Some(path) = parse_tab_path(url) else {
|
||||||
.query_pairs()
|
|
||||||
.find(|(k, _v)| k == "path")
|
|
||||||
.map(|(_, path)| PathBuf::from_str(&path))
|
|
||||||
else {
|
|
||||||
log::warn!("Could not parse path to open a new tab/window");
|
log::warn!("Could not parse path to open a new tab/window");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -533,3 +533,43 @@ fn validate_custom_uri_errors_do_not_leak_query_string() {
|
|||||||
assert!(!msg.contains("refresh_token"), "{msg}");
|
assert!(!msg.contains("refresh_token"), "{msg}");
|
||||||
assert!(!msg.contains("LEAKED"), "{msg}");
|
assert!(!msg.contains("LEAKED"), "{msg}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_tab_path_expands_tilde() {
|
||||||
|
let url = Url::parse("warp://action/new_tab?path=~/Projects").unwrap();
|
||||||
|
let home = dirs::home_dir().expect("HOME must be set for this test");
|
||||||
|
assert_eq!(parse_tab_path(&url), Some(home.join("Projects")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_tab_path_expands_url_encoded_tilde() {
|
||||||
|
// `%7E` and `%2F` are URL-encoded `~` and `/`.
|
||||||
|
let url = Url::parse("warp://action/new_tab?path=%7E%2FProjects").unwrap();
|
||||||
|
let home = dirs::home_dir().expect("HOME must be set for this test");
|
||||||
|
assert_eq!(parse_tab_path(&url), Some(home.join("Projects")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_tab_path_absolute_path_unchanged() {
|
||||||
|
let url = Url::parse("warp://action/new_tab?path=/tmp/foo").unwrap();
|
||||||
|
assert_eq!(parse_tab_path(&url), Some(PathBuf::from("/tmp/foo")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_tab_path_relative_path_unchanged() {
|
||||||
|
let url = Url::parse("warp://action/new_tab?path=relative/dir").unwrap();
|
||||||
|
assert_eq!(parse_tab_path(&url), Some(PathBuf::from("relative/dir")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_tab_path_missing_returns_none() {
|
||||||
|
let url = Url::parse("warp://action/new_tab").unwrap();
|
||||||
|
assert_eq!(parse_tab_path(&url), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_tab_path_bare_tilde() {
|
||||||
|
let url = Url::parse("warp://action/new_tab?path=~").unwrap();
|
||||||
|
let home = dirs::home_dir().expect("HOME must be set for this test");
|
||||||
|
assert_eq!(parse_tab_path(&url), Some(home));
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user