Clean up RelPath API (#38912)

Consolidate constructors and accessors.

Release Notes:

- N/A

---------

Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
Max Brunsfeld
2025-09-25 14:42:32 -07:00
committed by GitHub
co-authored by Cole Miller
parent 301e976465
commit 495a7b0a84
70 changed files with 483 additions and 408 deletions
+11 -5
View File
@@ -989,7 +989,7 @@ impl GitStore {
parse_git_remote_url(provider_registry, &origin_url)
.context("parsing Git remote URL")?;
let path = repo_path.as_str();
let path = repo_path.as_unix_str();
Ok(provider.build_permalink(
remote,
@@ -1315,7 +1315,7 @@ impl GitStore {
});
if let Some((repo, path)) = self.repository_and_path_for_buffer_id(buffer_id, cx) {
let recv = repo.update(cx, |repo, cx| {
log::debug!("hunks changed for {}", path.as_str());
log::debug!("hunks changed for {}", path.as_unix_str());
repo.spawn_set_index_text_job(
path,
new_index_text.as_ref().map(|rope| rope.to_string()),
@@ -3118,7 +3118,7 @@ impl Repository {
let repo_path = this.abs_path_to_repo_path(&abs_path)?;
log::debug!(
"start reload diff bases for repo path {}",
repo_path.as_str()
repo_path.as_unix_str()
);
diff_state.update(cx, |diff_state, _| {
let has_unstaged_diff = diff_state
@@ -4162,7 +4162,10 @@ impl Repository {
Some(GitJobKey::WriteIndex(path.clone())),
None,
move |git_repo, mut cx| async move {
log::debug!("start updating index text for buffer {}", path.as_str());
log::debug!(
"start updating index text for buffer {}",
path.as_unix_str()
);
match git_repo {
RepositoryState::Local {
backend,
@@ -4184,7 +4187,10 @@ impl Repository {
.await?;
}
}
log::debug!("finish updating index text for buffer {}", path.as_str());
log::debug!(
"finish updating index text for buffer {}",
path.as_unix_str()
);
if let Some(hunk_staging_operation_count) = hunk_staging_operation_count {
let project_path = this
@@ -332,7 +332,7 @@ mod tests {
let traversal = GitTraversal::new(
&repo_snapshots,
worktree_snapshot.traverse_from_path(true, false, true, RelPath::new("x").unwrap()),
worktree_snapshot.traverse_from_path(true, false, true, RelPath::unix("x").unwrap()),
);
let entries = traversal
.map(|entry| (entry.path.clone(), entry.git_summary))
+5 -8
View File
@@ -1850,7 +1850,7 @@ impl LocalLspStore {
if !extra_buffers.is_empty() {
extra_buffers.push_str(", ");
}
extra_buffers.push_str(path.path.as_str());
extra_buffers.push_str(path.path.as_unix_str());
}
})
.ok();
@@ -3284,7 +3284,7 @@ impl LocalLspStore {
let literal_prefix = glob_literal_prefix(relative);
Some((
worktree.clone(),
RelPath::from_std_path(&literal_prefix, path_style).ok()?,
RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
relative.to_string_lossy().to_string(),
))
}
@@ -3300,7 +3300,7 @@ impl LocalLspStore {
literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
Some((
worktree.clone(),
RelPath::from_std_path(&literal_prefix, path_style).ok()?,
RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
rp.pattern.clone(),
))
}
@@ -7936,11 +7936,8 @@ impl LspStore {
let relative_path = if let Some(known_path) = known_relative_path {
known_path
} else {
RelPath::from_std_path(
abs_path.strip_prefix(worktree_root)?,
PathStyle::local(),
)
.context("failed to create relative path")?
RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
.into_arc()
};
(worktree, relative_path)
};
@@ -61,7 +61,7 @@ impl<Label: Ord + Clone> RootPathTrie<Label> {
let mut path_so_far = <Arc<RelPath>>::from(RelPath::empty());
for key in path.0.iter() {
path_so_far = path_so_far.join(RelPath::new(key).unwrap());
path_so_far = path_so_far.join(RelPath::unix(key.as_ref()).unwrap());
current = match current.children.entry(key.clone()) {
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(RootPathTrie::new_with_key(path_so_far.clone()))
@@ -157,7 +157,7 @@ mod tests {
trie.walk(&TriePath::new(rel_path("a/b/c")), &mut |path, nodes| {
assert_eq!(nodes.get(&()), Some(&LabelPresence::Present));
assert_eq!(path.as_str(), "a/b/c");
assert_eq!(path.as_unix_str(), "a/b/c");
ControlFlow::Continue(())
});
// Now let's annotate a parent with "Known missing" node.
@@ -170,10 +170,10 @@ mod tests {
// Ensure that we walk from the root to the leaf.
let mut visited_paths = BTreeSet::new();
trie.walk(&TriePath::new(rel_path("a/b/c")), &mut |path, nodes| {
if path.as_str() == "a/b/c" {
if path.as_unix_str() == "a/b/c" {
assert_eq!(visited_paths, BTreeSet::from_iter([rel_path("a").into()]));
assert_eq!(nodes.get(&()), Some(&LabelPresence::Present));
} else if path.as_str() == "a" {
} else if path.as_unix_str() == "a" {
assert!(visited_paths.is_empty());
assert_eq!(nodes.get(&()), Some(&LabelPresence::KnownAbsent));
} else {
@@ -189,10 +189,10 @@ mod tests {
trie.walk(
&TriePath::new(rel_path("a/b/c/d/e/f/g")),
&mut |path, nodes| {
if path.as_str() == "a/b/c" {
if path.as_unix_str() == "a/b/c" {
assert_eq!(visited_paths, BTreeSet::from_iter([rel_path("a").into()]));
assert_eq!(nodes.get(&()), Some(&LabelPresence::Present));
} else if path.as_str() == "a" {
} else if path.as_unix_str() == "a" {
assert!(visited_paths.is_empty());
assert_eq!(nodes.get(&()), Some(&LabelPresence::KnownAbsent));
} else {
@@ -207,7 +207,7 @@ mod tests {
// Test breaking from the tree-walk.
let mut visited_paths = BTreeSet::new();
trie.walk(&TriePath::new(rel_path("a/b/c")), &mut |path, nodes| {
if path.as_str() == "a" {
if path.as_unix_str() == "a" {
assert!(visited_paths.is_empty());
assert_eq!(nodes.get(&()), Some(&LabelPresence::KnownAbsent));
} else {
@@ -254,8 +254,8 @@ mod tests {
let mut visited_paths = BTreeSet::new();
trie.walk(&TriePath::new(rel_path("a/b/c")), &mut |path, nodes| {
assert_eq!(nodes.get(&()), Some(&LabelPresence::Present));
if path.as_str() != "a" && path.as_str() != "a/b" {
panic!("Unexpected path: {}", path.as_str());
if path.as_unix_str() != "a" && path.as_unix_str() != "a/b" {
panic!("Unexpected path: {}", path.as_unix_str());
}
assert!(visited_paths.insert(path.clone()));
ControlFlow::Continue(())
+1 -1
View File
@@ -447,7 +447,7 @@ impl PrettierStore {
) {
let prettier_config_files = Prettier::CONFIG_FILE_NAMES
.iter()
.map(|name| RelPath::new(name).unwrap())
.map(|name| RelPath::unix(name).unwrap())
.collect::<HashSet<_>>();
let prettier_config_file_changed = changes
+13 -15
View File
@@ -2032,7 +2032,7 @@ impl Project {
pub fn worktree_root_names<'a>(&'a self, cx: &'a App) -> impl Iterator<Item = &'a str> {
self.visible_worktrees(cx)
.map(|tree| tree.read(cx).root_name().as_str())
.map(|tree| tree.read(cx).root_name().as_unix_str())
}
pub fn worktree_for_id(&self, id: WorktreeId, cx: &App) -> Option<Entity<Worktree>> {
@@ -4242,20 +4242,18 @@ impl Project {
cx: &mut Context<Self>,
) -> Task<Option<ResolvedPath>> {
let mut candidates = vec![];
if let Ok(path) = RelPath::from_std_path(Path::new(path), self.path_style(cx)) {
candidates.push(path);
let path_style = self.path_style(cx);
if let Ok(path) = RelPath::new(path.as_ref(), path_style) {
candidates.push(path.into_arc());
}
if let Some(file) = buffer.read(cx).file()
&& let Some(dir) = file.path().parent()
{
if let Some(joined) = self
.path_style(cx)
.join(&*dir.display(self.path_style(cx)), path)
&& let Some(joined) =
RelPath::from_std_path(Path::new(&joined), self.path_style(cx)).ok()
if let Some(joined) = path_style.join(&*dir.display(path_style), path)
&& let Some(joined) = RelPath::new(joined.as_ref(), path_style).ok()
{
candidates.push(joined);
candidates.push(joined.into_arc());
}
}
@@ -4470,30 +4468,30 @@ impl Project {
let worktree_abs_path = worktree.read(cx).abs_path();
if let Ok(relative_path) = path.strip_prefix(worktree_abs_path)
&& let Ok(path) = RelPath::from_std_path(relative_path, path_style)
&& let Ok(path) = RelPath::new(relative_path, path_style)
{
return Some(ProjectPath {
worktree_id: worktree.read(cx).id(),
path,
path: path.into_arc(),
});
}
}
} else {
for worktree in worktree_store.visible_worktrees(cx) {
let worktree_root_name = worktree.read(cx).root_name();
if let Ok(relative_path) = path.strip_prefix(worktree_root_name)
&& let Ok(path) = RelPath::from_std_path(relative_path, path_style)
if let Ok(relative_path) = path.strip_prefix(worktree_root_name.as_std_path())
&& let Ok(path) = RelPath::new(relative_path, path_style)
{
return Some(ProjectPath {
worktree_id: worktree.read(cx).id(),
path,
path: path.into_arc(),
});
}
}
for worktree in worktree_store.visible_worktrees(cx) {
let worktree = worktree.read(cx);
if let Ok(path) = RelPath::from_std_path(path, path_style)
if let Ok(path) = RelPath::new(path, path_style)
&& let Some(entry) = worktree.entry_for_path(&path)
{
return Some(ProjectPath {
+6 -6
View File
@@ -859,7 +859,7 @@ impl SettingsObserver {
.unwrap()
.into();
(settings_dir, LocalSettingsKind::Debug)
} else if path.ends_with(RelPath::new(EDITORCONFIG_NAME).unwrap()) {
} else if path.ends_with(RelPath::unix(EDITORCONFIG_NAME).unwrap()) {
let Some(settings_dir) = path.parent().map(Arc::from) else {
continue;
};
@@ -881,7 +881,7 @@ impl SettingsObserver {
Some(
async move {
let content = fs.load(&abs_path).await?;
if abs_path.ends_with(local_vscode_tasks_file_relative_path()) {
if abs_path.ends_with(local_vscode_tasks_file_relative_path().as_std_path()) {
let vscode_tasks =
parse_json_with_comments::<VsCodeTaskFile>(&content)
.with_context(|| {
@@ -898,7 +898,7 @@ impl SettingsObserver {
"serializing Zed tasks into JSON, file {abs_path:?}"
)
})
} else if abs_path.ends_with(local_vscode_launch_file_relative_path()) {
} else if abs_path.ends_with(local_vscode_launch_file_relative_path().as_std_path()) {
let vscode_tasks =
parse_json_with_comments::<VsCodeDebugTaskFile>(&content)
.with_context(|| {
@@ -984,7 +984,7 @@ impl SettingsObserver {
Ok(()) => {
cx.emit(SettingsObserverEvent::LocalSettingsUpdated(Ok(directory
.as_std_path()
.join(local_settings_file_relative_path()))));
.join(local_settings_file_relative_path().as_std_path()))));
}
}
}),
@@ -1013,7 +1013,7 @@ impl SettingsObserver {
Ok(()) => {
cx.emit(SettingsObserverEvent::LocalTasksUpdated(Ok(directory
.as_std_path()
.join(RelPath::new(task_file_name()).unwrap()))));
.join(task_file_name()))));
}
}
}
@@ -1044,7 +1044,7 @@ impl SettingsObserver {
Ok(()) => {
cx.emit(SettingsObserverEvent::LocalTasksUpdated(Ok(directory
.as_std_path()
.join(RelPath::new(task_file_name()).unwrap()))));
.join(task_file_name()))));
}
}
}
+5 -5
View File
@@ -608,7 +608,7 @@ async fn test_running_multiple_instances_of_a_single_server_in_one_worktree(
}: ManifestQuery,
) -> Option<Arc<RelPath>> {
for path in path.ancestors().take(depth) {
let p = path.join(RelPath::new("pyproject.toml").unwrap());
let p = path.join(rel_path("pyproject.toml"));
if delegate.exists(&p, Some(false)) {
return Some(path.into());
}
@@ -737,7 +737,7 @@ async fn test_running_multiple_instances_of_a_single_server_in_one_worktree(
})
.await
.expect("A toolchain to be discovered");
assert_eq!(root_path.as_ref(), RelPath::new("project-b").unwrap());
assert_eq!(root_path.as_ref(), rel_path("project-b"));
assert_eq!(available_toolchains_for_b.toolchains().len(), 1);
let currently_active_toolchain = project
.update(cx, |this, cx| {
@@ -1285,7 +1285,7 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
.read(cx)
.snapshot()
.entries(true, 0)
.map(|entry| (entry.path.as_str(), entry.is_ignored))
.map(|entry| (entry.path.as_unix_str(), entry.is_ignored))
.collect::<Vec<_>>(),
&[
("", false),
@@ -1403,7 +1403,7 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
.read(cx)
.snapshot()
.entries(true, 0)
.map(|entry| (entry.path.as_str(), entry.is_ignored))
.map(|entry| (entry.path.as_unix_str(), entry.is_ignored))
.collect::<Vec<_>>(),
&[
("", false),
@@ -9336,7 +9336,7 @@ fn python_lang(fs: Arc<FakeFs>) -> Arc<Language> {
let ancestors = subroot_relative_path.ancestors().collect::<Vec<_>>();
let mut toolchains = vec![];
for ancestor in ancestors {
let venv_path = worktree_root.join(ancestor).join(".venv");
let venv_path = worktree_root.join(ancestor.as_std_path()).join(".venv");
if self.0.is_dir(&venv_path).await {
toolchains.push(Toolchain {
name: SharedString::new("Python Venv"),
+4 -4
View File
@@ -228,7 +228,7 @@ impl TaskSourceKind {
id_base,
directory_in_worktree,
} => {
format!("{id_base}_{id}_{}", directory_in_worktree.as_str())
format!("{id_base}_{id}_{}", directory_in_worktree.as_unix_str())
}
Self::Language { name } => format!("language_{name}"),
Self::Lsp {
@@ -1182,7 +1182,7 @@ mod tests {
let worktree_id = WorktreeId::from_usize(0);
let local_worktree_location = SettingsLocation {
worktree_id,
path: RelPath::new("foo").unwrap(),
path: rel_path("foo"),
};
inventory.update(cx, |inventory, _| {
inventory
@@ -1476,7 +1476,7 @@ mod tests {
.update_file_based_tasks(
TaskSettingsLocation::Worktree(SettingsLocation {
worktree_id: worktree_1,
path: RelPath::new(".zed").unwrap(),
path: rel_path(".zed"),
}),
Some(&mock_tasks_from_names(
worktree_1_tasks.iter().map(|(_, name)| name.as_str()),
@@ -1487,7 +1487,7 @@ mod tests {
.update_file_based_tasks(
TaskSettingsLocation::Worktree(SettingsLocation {
worktree_id: worktree_2,
path: RelPath::new(".zed").unwrap(),
path: rel_path(".zed"),
}),
Some(&mock_tasks_from_names(
worktree_2_tasks.iter().map(|(_, name)| name.as_str()),
+1 -1
View File
@@ -257,7 +257,7 @@ impl ToolchainStore {
envelope: TypedEnvelope<proto::ActiveToolchain>,
mut cx: AsyncApp,
) -> Result<proto::ActiveToolchainResponse> {
let path = RelPath::new(envelope.payload.path.as_deref().unwrap_or(""))?;
let path = RelPath::unix(envelope.payload.path.as_deref().unwrap_or(""))?;
let toolchain = this
.update(&mut cx, |this, cx| {
let language_name = LanguageName::from_proto(envelope.payload.language_name);
+5 -5
View File
@@ -161,9 +161,9 @@ impl WorktreeStore {
for tree in self.worktrees() {
let path_style = tree.read(cx).path_style();
if let Ok(relative_path) = abs_path.as_ref().strip_prefix(tree.read(cx).abs_path())
&& let Ok(relative_path) = RelPath::from_std_path(relative_path, path_style)
&& let Ok(relative_path) = RelPath::new(relative_path, path_style)
{
return Some((tree.clone(), relative_path));
return Some((tree.clone(), relative_path.into_arc()));
}
}
None
@@ -1025,9 +1025,9 @@ impl WorktreeStore {
continue;
}
let relative_path = file.strip_prefix(snapshot.abs_path())?;
let relative_path = RelPath::from_std_path(&relative_path, snapshot.path_style())
let relative_path = RelPath::new(&relative_path, snapshot.path_style())
.context("getting relative path")?;
results.push((relative_path, !metadata.is_dir))
results.push((relative_path.into_arc(), !metadata.is_dir))
}
results.sort_by(|(a_path, _), (b_path, _)| a_path.cmp(b_path));
for (path, is_file) in results {
@@ -1052,7 +1052,7 @@ impl WorktreeStore {
worktree_root: snapshot.abs_path().clone(),
path: ProjectPath {
worktree_id: snapshot.id(),
path,
path: path.into_arc(),
},
})
.await?;
+2 -3
View File
@@ -114,9 +114,8 @@ impl YarnPathStore {
};
// Rebase zip-path onto new temp path.
let as_relative =
RelPath::from_std_path(path.strip_prefix(zip_file).ok()?, PathStyle::local())
.ok()?;
Some((zip_root.into(), as_relative))
RelPath::new(path.strip_prefix(zip_file).ok()?, PathStyle::local()).ok()?;
Some((zip_root.into(), as_relative.into_arc()))
})
} else {
Task::ready(None)