History

Support `find_project_path` being given absolute paths (#30283)

Sometimes models return absolute paths even though we ask them not to (including sometimes returning `/dev/null`). Currently we assume we're always given a relative path, which leads to a panic in debug builds. Now we just support being given absolute paths. Release Notes: - N/A ---------

Richard Feldman committed 1 year ago

Commit 77945fc1 parent 6827bf12 files · +114 −15Browse files

Unified · Split

2 files
  1. crates/project/src/project.rs +28 −15
  2. crates/project/src/project_tests.rs +86 −0
crates/project/src/project.rs+28−15
@@ -4163,23 +4163,36 @@ impl Project { · 4162 unmodified lines
41634163 let path = path.as_ref();
41644164 let worktree_store = self.worktree_store.read(cx);
41654165
4166− for worktree in worktree_store.visible_worktrees(cx) {
4167− let worktree_root_name = worktree.read(cx).root_name();
4168− if let Ok(relative_path) = path.strip_prefix(worktree_root_name) {
4169− return Some(ProjectPath {
4170− worktree_id: worktree.read(cx).id(),
4171− path: relative_path.into(),
4172− });
4166+ if path.is_absolute() {
4167+ for worktree in worktree_store.visible_worktrees(cx) {
4168+ let worktree_abs_path = worktree.read(cx).abs_path();
4169+
4170+ if let Ok(relative_path) = path.strip_prefix(worktree_abs_path) {
4171+ return Some(ProjectPath {
4172+ worktree_id: worktree.read(cx).id(),
4173+ path: relative_path.into(),
4174+ });
4175+ }
4176+ }
4177+ } else {
4178+ for worktree in worktree_store.visible_worktrees(cx) {
4179+ let worktree_root_name = worktree.read(cx).root_name();
4180+ if let Ok(relative_path) = path.strip_prefix(worktree_root_name) {
4181+ return Some(ProjectPath {
4182+ worktree_id: worktree.read(cx).id(),
4183+ path: relative_path.into(),
4184+ });
4185+ }
41734186 }
4174− }
41754187
4176− for worktree in worktree_store.visible_worktrees(cx) {
4177− let worktree = worktree.read(cx);
4178− if let Some(entry) = worktree.entry_for_path(path) {
4179− return Some(ProjectPath {
4180− worktree_id: worktree.id(),
4181− path: entry.path.clone(),
4182− });
4188+ for worktree in worktree_store.visible_worktrees(cx) {
4189+ let worktree = worktree.read(cx);
4190+ if let Some(entry) = worktree.entry_for_path(path) {
4191+ return Some(ProjectPath {
4192+ worktree_id: worktree.id(),
4193+ path: entry.path.clone(),
4194+ });
4195+ }
41834196 }
41844197 }
41854198
crates/project/src/project_tests.rs+86−0
@@ -8766,3 +8766,89 @@ fn git_status(repo: &git2::Repository) -> collections::HashMap<String, git2::Sta · 8765 unmodified lines
87668766 .map(|status| (status.path().unwrap().to_string(), status.status()))
87678767 .collect()
87688768 }
8769+
8770+#[gpui::test]
8771+async fn test_find_project_path_abs(
8772+ background_executor: BackgroundExecutor,
8773+ cx: &mut gpui::TestAppContext,
8774+) {
8775+ // find_project_path should work with absolute paths
8776+ init_test(cx);
8777+
8778+ let fs = FakeFs::new(background_executor);
8779+ fs.insert_tree(
8780+ path!("/root"),
8781+ json!({
8782+ "project1": {
8783+ "file1.txt": "content1",
8784+ "subdir": {
8785+ "file2.txt": "content2"
8786+ }
8787+ },
8788+ "project2": {
8789+ "file3.txt": "content3"
8790+ }
8791+ }),
8792+ )
8793+ .await;
8794+
8795+ let project = Project::test(
8796+ fs.clone(),
8797+ [
8798+ path!("/root/project1").as_ref(),
8799+ path!("/root/project2").as_ref(),
8800+ ],
8801+ cx,
8802+ )
8803+ .await;
8804+
8805+ // Make sure the worktrees are fully initialized
8806+ for worktree in project.read_with(cx, |project, cx| project.worktrees(cx).collect::<Vec<_>>()) {
8807+ worktree
8808+ .read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete())
8809+ .await;
8810+ }
8811+ cx.run_until_parked();
8812+
8813+ let (project1_abs_path, project1_id, project2_abs_path, project2_id) =
8814+ project.read_with(cx, |project, cx| {
8815+ let worktrees: Vec<_> = project.worktrees(cx).collect();
8816+ let abs_path1 = worktrees[0].read(cx).abs_path().to_path_buf();
8817+ let id1 = worktrees[0].read(cx).id();
8818+ let abs_path2 = worktrees[1].read(cx).abs_path().to_path_buf();
8819+ let id2 = worktrees[1].read(cx).id();
8820+ (abs_path1, id1, abs_path2, id2)
8821+ });
8822+
8823+ project.update(cx, |project, cx| {
8824+ let abs_path = project1_abs_path.join("file1.txt");
8825+ let found_path = project.find_project_path(abs_path, cx).unwrap();
8826+ assert_eq!(found_path.worktree_id, project1_id);
8827+ assert_eq!(found_path.path.as_ref(), Path::new("file1.txt"));
8828+
8829+ let abs_path = project1_abs_path.join("subdir").join("file2.txt");
8830+ let found_path = project.find_project_path(abs_path, cx).unwrap();
8831+ assert_eq!(found_path.worktree_id, project1_id);
8832+ assert_eq!(found_path.path.as_ref(), Path::new("subdir/file2.txt"));
8833+
8834+ let abs_path = project2_abs_path.join("file3.txt");
8835+ let found_path = project.find_project_path(abs_path, cx).unwrap();
8836+ assert_eq!(found_path.worktree_id, project2_id);
8837+ assert_eq!(found_path.path.as_ref(), Path::new("file3.txt"));
8838+
8839+ let abs_path = project1_abs_path.join("nonexistent.txt");
8840+ let found_path = project.find_project_path(abs_path, cx);
8841+ assert!(
8842+ found_path.is_some(),
8843+ "Should find project path for nonexistent file in worktree"
8844+ );
8845+
8846+ // Test with an absolute path outside any worktree
8847+ let abs_path = Path::new("/some/other/path");
8848+ let found_path = project.find_project_path(abs_path, cx);
8849+ assert!(
8850+ found_path.is_none(),
8851+ "Should not find project path for path outside any worktree"
8852+ );
8853+ });
8854+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t