diff --git a/crates/moon-util/src/rel_path.rs b/crates/moon-util/src/rel_path.rs index e0e2625..8e15c39 100644 --- a/crates/moon-util/src/rel_path.rs +++ b/crates/moon-util/src/rel_path.rs @@ -52,6 +52,11 @@ impl RelPath { #[track_caller] pub fn new<'a>(path: &'a Path, path_style: PathStyle) -> Result> { let mut path = path.to_str().context("non utf-8 path")?; + // Check before trimming trailing separators: trimming turns the drive + // root `C:\` into `C:`, which no longer reads as absolute. + if is_absolute(path, path_style) { + return Err(anyhow!("absolute path not allowed: {path:?}")); + } let (prefixes, suffixes): (&[_], &[_]) = match path_style { PathStyle::Posix => (&["./"], &['/']), diff --git a/crates/moon-util/src/rel_path/rel_path_tests.rs b/crates/moon-util/src/rel_path/rel_path_tests.rs index 97136a3..c23976c 100644 --- a/crates/moon-util/src/rel_path/rel_path_tests.rs +++ b/crates/moon-util/src/rel_path/rel_path_tests.rs @@ -221,3 +221,19 @@ fn from_proto_accepts_only_an_already_normalized_relative_path() { "an absolute path is not a relative wire path" ); } + +/// Catches `RelPath::new` stripping trailing separators before it checks for an +/// absolute path, so the Windows drive root `C:\` (absolute by +/// `paths::is_absolute`: drive letter, colon, separator) loses its separator and +/// is accepted as the relative path `C:`. `C:\foo` and `C:\.` are rejected, so +/// the bare root must be too; a caller such as `PathStyle::strip_prefix` would +/// otherwise hand out a drive root as a path inside the worktree. +#[test] +fn new_rejects_a_windows_drive_root() { + for root in ["C:\\", "C:/", "d:\\\\"] { + assert!( + super::RelPath::new(std::path::Path::new(root), PathStyle::Windows).is_err(), + "{root:?} is an absolute drive root, not a relative path" + ); + } +} diff --git a/docs/MOON_PATCH_QUEUE.md b/docs/MOON_PATCH_QUEUE.md index 2b2fe98..237368d 100644 --- a/docs/MOON_PATCH_QUEUE.md +++ b/docs/MOON_PATCH_QUEUE.md @@ -57,6 +57,13 @@ cargo xtask transform --zed-tag v0.0.0 --zed-path R:\test\_zed_gpui_base_84b753 - regular pointer tooltips require 800 ms of continuous hover, expire after five visible seconds, and stay suppressed until pointer re-entry; hoverable tooltips remain persistent while either their trigger or content is hovered. + A mouse press on the trigger of a regular tooltip hides it, or cancels the + pending show, and keeps it suppressed until the pointer leaves the trigger, + even with the button still held (`TooltipTrigger` in + `moon-gpui/src/elements/div.rs`: `check_can_show` gates showing, + `check_is_hovered` clears the suppression). Upstream only clears the + tooltip on press; after the release the next pointer move over the + trigger schedules it again without the pointer leaving. - `UniformList::on_visible_range`: a channel for observing the item range the list draws. The renderer closure cannot serve as one — `measure_item` runs it on a single item, twice per frame, before the real range exists — so a