Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T05:17:56.225Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

terminal_path_like_target.rs

1006 lines · 33.5 KB · rust
1use super::{HoverTarget, HoveredWord, TerminalView};
2use anyhow::Result;
3use editor::items::open_resolved_target;
4use gpui::{Context, Task, TaskExt, WeakEntity, Window};
5use std::path::PathBuf;
6use terminal::PathLikeTarget;
7#[cfg(not(test))]
8use workspace::path_link::possible_open_target;
9#[cfg(test)]
10use workspace::path_link::{
11    BackgroundPathChecks, OpenTargetFoundBy, possible_open_target_with_fs_checks,
12};
13use workspace::{Workspace, path_link::OpenTarget};
14
15pub(super) fn hover_path_like_target(
16    workspace: &WeakEntity<Workspace>,
17    hovered_word: HoveredWord,
18    path_like_target: &PathLikeTarget,
19    cx: &mut Context<TerminalView>,
20) -> Task<()> {
21    #[cfg(not(test))]
22    {
23        possible_hover_target(workspace, hovered_word, path_like_target, cx)
24    }
25    #[cfg(test)]
26    {
27        possible_hover_target(
28            workspace,
29            hovered_word,
30            path_like_target,
31            cx,
32            BackgroundPathChecks::LocalFileSystem,
33        )
34    }
35}
36
37fn possible_hover_target(
38    workspace: &WeakEntity<Workspace>,
39    hovered_word: HoveredWord,
40    path_like_target: &PathLikeTarget,
41    cx: &mut Context<TerminalView>,
42    #[cfg(test)] background_path_checks: BackgroundPathChecks,
43) -> Task<()> {
44    #[cfg(not(test))]
45    let file_to_open_task = possible_open_target(
46        workspace,
47        &path_like_target.maybe_path,
48        path_like_target.terminal_dir.as_deref(),
49        cx,
50    );
51    #[cfg(test)]
52    let file_to_open_task = possible_open_target_with_fs_checks(
53        workspace,
54        &path_like_target.maybe_path,
55        path_like_target.terminal_dir.as_deref(),
56        cx,
57        background_path_checks,
58    );
59    cx.spawn(async move |terminal_view, cx| {
60        let file_to_open = file_to_open_task.await;
61        terminal_view
62            .update(cx, |terminal_view, _| match file_to_open {
63                Some(OpenTarget::Path(path, ..) | OpenTarget::Worktree(path, ..)) => {
64                    terminal_view.hover = Some(HoverTarget {
65                        tooltip: path
66                            .to_string(&|path: &PathBuf| path.to_string_lossy().into_owned()),
67                        hovered_word,
68                    });
69                }
70                None => {
71                    terminal_view.hover = None;
72                }
73            })
74            .ok();
75    })
76}
77
78pub(super) fn open_path_like_target(
79    workspace: &WeakEntity<Workspace>,
80    terminal_view: &mut TerminalView,
81    path_like_target: &PathLikeTarget,
82    window: &mut Window,
83    cx: &mut Context<TerminalView>,
84) {
85    #[cfg(not(test))]
86    {
87        possibly_open_target(workspace, terminal_view, path_like_target, window, cx)
88            .detach_and_log_err(cx)
89    }
90    #[cfg(test)]
91    {
92        possibly_open_target(
93            workspace,
94            terminal_view,
95            path_like_target,
96            window,
97            cx,
98            BackgroundPathChecks::LocalFileSystem,
99        )
100        .detach_and_log_err(cx)
101    }
102}
103
104fn possibly_open_target(
105    workspace: &WeakEntity<Workspace>,
106    terminal_view: &mut TerminalView,
107    path_like_target: &PathLikeTarget,
108    window: &mut Window,
109    cx: &mut Context<TerminalView>,
110    #[cfg(test)] background_path_checks: BackgroundPathChecks,
111) -> Task<Result<Option<OpenTarget>>> {
112    if terminal_view.hover.is_none() {
113        return Task::ready(Ok(None));
114    }
115    let workspace = workspace.clone();
116    let path_like_target = path_like_target.clone();
117    cx.spawn_in(window, async move |terminal_view, cx| {
118        let Some(open_target) = terminal_view
119            .update(cx, |_, cx| {
120                #[cfg(not(test))]
121                {
122                    possible_open_target(
123                        &workspace,
124                        &path_like_target.maybe_path,
125                        path_like_target.terminal_dir.as_deref(),
126                        cx,
127                    )
128                }
129                #[cfg(test)]
130                {
131                    possible_open_target_with_fs_checks(
132                        &workspace,
133                        &path_like_target.maybe_path,
134                        path_like_target.terminal_dir.as_deref(),
135                        cx,
136                        background_path_checks,
137                    )
138                }
139            })?
140            .await
141        else {
142            return Ok(None);
143        };
144
145        let opened = open_resolved_target(&workspace, &open_target, cx).await?;
146        Ok(opened.then_some(open_target))
147    })
148}
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153    use gpui::{AppContext as _, TestAppContext};
154    use project::Project;
155    use serde_json::json;
156    use std::path::{Path, PathBuf};
157    use terminal::{
158        HoveredWord, Point, Range, TerminalBuilder,
159        terminal_settings::{AlternateScroll, CursorShape},
160    };
161    use util::path;
162    use util::paths::PathStyle;
163    use workspace::{AppState, MultiWorkspace};
164
165    async fn init_test(
166        app_cx: &mut TestAppContext,
167        trees: impl IntoIterator<Item = (&str, serde_json::Value)>,
168        worktree_roots: impl IntoIterator<Item = &str>,
169    ) -> impl AsyncFnMut(
170        HoveredWord,
171        PathLikeTarget,
172        BackgroundPathChecks,
173    ) -> (Option<HoverTarget>, Option<OpenTarget>) {
174        let fs = app_cx.update(AppState::test).fs.as_fake().clone();
175
176        app_cx.update(|cx| {
177            theme_settings::init(theme::LoadThemes::JustBase, cx);
178            editor::init(cx);
179        });
180
181        for (path, tree) in trees {
182            fs.insert_tree(path, tree).await;
183        }
184
185        let project: gpui::Entity<Project> = Project::test(
186            fs.clone(),
187            worktree_roots.into_iter().map(Path::new),
188            app_cx,
189        )
190        .await;
191
192        let (multi_workspace, cx) = app_cx
193            .add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
194        let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
195
196        let terminal = app_cx.new(|cx| {
197            TerminalBuilder::new_display_only(
198                CursorShape::default(),
199                AlternateScroll::On,
200                None,
201                0,
202                cx.background_executor(),
203                PathStyle::local(),
204            )
205            .subscribe(cx)
206        });
207
208        let workspace_a = workspace.clone();
209        let (terminal_view, cx) = app_cx.add_window_view(|window, cx| {
210            TerminalView::new(
211                terminal,
212                workspace_a.downgrade(),
213                None,
214                project.downgrade(),
215                window,
216                cx,
217            )
218        });
219
220        async move |hovered_word: HoveredWord,
221                    path_like_target: PathLikeTarget,
222                    background_path_checks: BackgroundPathChecks|
223                    -> (Option<HoverTarget>, Option<OpenTarget>) {
224            let workspace_a = workspace.clone();
225            terminal_view
226                .update(cx, |_, cx| {
227                    possible_hover_target(
228                        &workspace_a.downgrade(),
229                        hovered_word,
230                        &path_like_target,
231                        cx,
232                        background_path_checks,
233                    )
234                })
235                .await;
236
237            let hover_target =
238                terminal_view.read_with(cx, |terminal_view, _| terminal_view.hover.clone());
239
240            let open_target = terminal_view
241                .update_in(cx, |terminal_view, window, cx| {
242                    possibly_open_target(
243                        &workspace.downgrade(),
244                        terminal_view,
245                        &path_like_target,
246                        window,
247                        cx,
248                        background_path_checks,
249                    )
250                })
251                .await
252                .expect("Failed to possibly open target");
253
254            (hover_target, open_target)
255        }
256    }
257
258    async fn test_path_like_simple(
259        test_path_like: &mut impl AsyncFnMut(
260            HoveredWord,
261            PathLikeTarget,
262            BackgroundPathChecks,
263        ) -> (Option<HoverTarget>, Option<OpenTarget>),
264        maybe_path: &str,
265        tooltip: &str,
266        terminal_dir: Option<PathBuf>,
267        background_path_checks: BackgroundPathChecks,
268        open_target_found_by: OpenTargetFoundBy,
269        file: &str,
270        line: u32,
271    ) {
272        let (hover_target, open_target) = test_path_like(
273            HoveredWord {
274                word: maybe_path.to_string(),
275                word_match: Range::new(Point::new(0, 0), Point::new(0, 0)),
276                id: 0,
277            },
278            PathLikeTarget {
279                maybe_path: maybe_path.to_string(),
280                terminal_dir,
281            },
282            background_path_checks,
283        )
284        .await;
285
286        let Some(hover_target) = hover_target else {
287            assert!(
288                hover_target.is_some(),
289                "Hover target should not be `None` at {file}:{line}:"
290            );
291            return;
292        };
293
294        assert_eq!(
295            hover_target.tooltip, tooltip,
296            "Tooltip mismatch at {file}:{line}:"
297        );
298        assert_eq!(
299            hover_target.hovered_word.word, maybe_path,
300            "Hovered word mismatch at {file}:{line}:"
301        );
302
303        let Some(open_target) = open_target else {
304            assert!(
305                open_target.is_some(),
306                "Open target should not be `None` at {file}:{line}:"
307            );
308            return;
309        };
310
311        assert_eq!(
312            open_target.path().path,
313            Path::new(tooltip),
314            "Open target path mismatch at {file}:{line}:"
315        );
316
317        assert_eq!(
318            open_target.found_by(),
319            open_target_found_by,
320            "Open target found by mismatch at {file}:{line}:"
321        );
322    }
323
324    macro_rules! none_or_some_pathbuf {
325        (None) => {
326            None
327        };
328        ($cwd:literal) => {
329            Some($crate::PathBuf::from(path!($cwd)))
330        };
331    }
332
333    macro_rules! test_path_like {
334        (
335            $test_path_like:expr,
336            $maybe_path:literal,
337            $tooltip:literal,
338            $cwd:tt,
339            $found_by:expr
340        ) => {{
341            test_path_like!(
342                $test_path_like,
343                $maybe_path,
344                $tooltip,
345                $cwd,
346                BackgroundPathChecks::LocalFileSystem,
347                $found_by
348            );
349            test_path_like!(
350                $test_path_like,
351                $maybe_path,
352                $tooltip,
353                $cwd,
354                BackgroundPathChecks::ProjectPathResolution,
355                $found_by
356            );
357        }};
358
359        (
360            $test_path_like:expr,
361            $maybe_path:literal,
362            $tooltip:literal,
363            $cwd:tt,
364            $background_fs_checks:path,
365            $found_by:expr
366        ) => {
367            test_path_like_simple(
368                &mut $test_path_like,
369                path!($maybe_path),
370                path!($tooltip),
371                none_or_some_pathbuf!($cwd),
372                $background_fs_checks,
373                $found_by,
374                std::file!(),
375                std::line!(),
376            )
377            .await
378        };
379    }
380
381    // Note the arms of `test`, `test_local`, and `test_remote` should be collapsed once macro
382    // metavariable expressions (#![feature(macro_metavar_expr)]) are stabilized.
383    // See https://github.com/rust-lang/rust/issues/83527
384    #[doc = "test_path_likes!(<cx>, <trees>, <worktrees>, { $(<tests>;)+ })"]
385    macro_rules! test_path_likes {
386        ($cx:expr, $trees:expr, $worktrees:expr, { $($tests:expr;)+ }) => { {
387            let mut test_path_like = init_test($cx, $trees, $worktrees).await;
388            #[doc ="test!(<hovered maybe_path>, <expected tooltip>, <terminal cwd> "]
389            #[doc ="\\[, found by \\])"]
390            #[allow(unused_macros)]
391            macro_rules! test {
392                ($maybe_path:literal, $tooltip:literal, $cwd:tt) => {
393                    test_path_like!(
394                        test_path_like,
395                        $maybe_path,
396                        $tooltip,
397                        $cwd,
398                        OpenTargetFoundBy::WorktreeExact
399                    )
400                };
401                ($maybe_path:literal, $tooltip:literal, $cwd:tt, $found_by:ident) => {
402                    test_path_like!(
403                        test_path_like,
404                        $maybe_path,
405                        $tooltip,
406                        $cwd,
407                        OpenTargetFoundBy::$found_by
408                    )
409                }
410            }
411            #[doc ="test_local!(<hovered maybe_path>, <expected tooltip>, <terminal cwd> "]
412            #[doc ="\\[, found by \\])"]
413            #[allow(unused_macros)]
414            macro_rules! test_local {
415                ($maybe_path:literal, $tooltip:literal, $cwd:tt) => {
416                    test_path_like!(
417                        test_path_like,
418                        $maybe_path,
419                        $tooltip,
420                        $cwd,
421                        BackgroundPathChecks::LocalFileSystem,
422                        OpenTargetFoundBy::WorktreeExact
423                    )
424                };
425                ($maybe_path:literal, $tooltip:literal, $cwd:tt, $found_by:ident) => {
426                    test_path_like!(
427                        test_path_like,
428                        $maybe_path,
429                        $tooltip,
430                        $cwd,
431                        BackgroundPathChecks::LocalFileSystem,
432                        OpenTargetFoundBy::$found_by
433                    )
434                }
435            }
436            #[doc ="test_remote!(<hovered maybe_path>, <expected tooltip>, <terminal cwd> "]
437            #[doc ="\\[, found by \\])"]
438            #[allow(unused_macros)]
439            macro_rules! test_remote {
440                ($maybe_path:literal, $tooltip:literal, $cwd:tt) => {
441                    test_path_like!(
442                        test_path_like,
443                        $maybe_path,
444                        $tooltip,
445                        $cwd,
446                        BackgroundPathChecks::ProjectPathResolution,
447                        OpenTargetFoundBy::WorktreeExact
448                    )
449                };
450                ($maybe_path:literal, $tooltip:literal, $cwd:tt, $found_by:ident) => {
451                    test_path_like!(
452                        test_path_like,
453                        $maybe_path,
454                        $tooltip,
455                        $cwd,
456                        BackgroundPathChecks::ProjectPathResolution,
457                        OpenTargetFoundBy::$found_by
458                    )
459                }
460            }
461            $($tests);+
462        } }
463    }
464
465    #[gpui::test]
466    async fn one_folder_worktree(cx: &mut TestAppContext) {
467        test_path_likes!(
468            cx,
469            vec![(
470                path!("/test"),
471                json!({
472                    "lib.rs": "",
473                    "test.rs": "",
474                }),
475            )],
476            vec![path!("/test")],
477            {
478                test!("lib.rs", "/test/lib.rs", None);
479                test!("/test/lib.rs", "/test/lib.rs", None);
480                test!("test.rs", "/test/test.rs", None);
481                test!("/test/test.rs", "/test/test.rs", None);
482            }
483        )
484    }
485
486    #[gpui::test]
487    async fn mixed_worktrees(cx: &mut TestAppContext) {
488        test_path_likes!(
489            cx,
490            vec![
491                (
492                    path!("/"),
493                    json!({
494                        "file.txt": "",
495                    }),
496                ),
497                (
498                    path!("/test"),
499                    json!({
500                        "lib.rs": "",
501                        "test.rs": "",
502                        "file.txt": "",
503                    }),
504                ),
505            ],
506            vec![path!("/file.txt"), path!("/test")],
507            {
508                test!("file.txt", "/file.txt", "/");
509                test!("/file.txt", "/file.txt", "/");
510
511                test!("lib.rs", "/test/lib.rs", "/test");
512                test!("test.rs", "/test/test.rs", "/test");
513                test!("file.txt", "/test/file.txt", "/test");
514
515                test!("/test/lib.rs", "/test/lib.rs", "/test");
516                test!("/test/test.rs", "/test/test.rs", "/test");
517                test!("/test/file.txt", "/test/file.txt", "/test");
518            }
519        )
520    }
521
522    #[gpui::test]
523    async fn worktree_file_preferred(cx: &mut TestAppContext) {
524        test_path_likes!(
525            cx,
526            vec![
527                (
528                    path!("/"),
529                    json!({
530                        "file.txt": "",
531                    }),
532                ),
533                (
534                    path!("/test"),
535                    json!({
536                        "file.txt": "",
537                    }),
538                ),
539            ],
540            vec![path!("/test")],
541            {
542                test!("file.txt", "/test/file.txt", "/test");
543            }
544        )
545    }
546
547    mod issues {
548        use super::*;
549
550        // https://github.com/zed-industries/zed/issues/28407
551        #[gpui::test]
552        async fn issue_28407_siblings(cx: &mut TestAppContext) {
553            test_path_likes!(
554                cx,
555                vec![(
556                    path!("/dir1"),
557                    json!({
558                        "dir 2": {
559                            "C.py": ""
560                        },
561                        "dir 3": {
562                            "C.py": ""
563                        },
564                    }),
565                )],
566                vec![path!("/dir1")],
567                {
568                    test!("C.py", "/dir1/dir 2/C.py", "/dir1", WorktreeScan);
569                    test!("C.py", "/dir1/dir 2/C.py", "/dir1/dir 2");
570                    test!("C.py", "/dir1/dir 3/C.py", "/dir1/dir 3");
571                }
572            )
573        }
574
575        // https://github.com/zed-industries/zed/issues/28407
576        // See https://github.com/zed-industries/zed/issues/34027
577        // See https://github.com/zed-industries/zed/issues/33498
578        #[gpui::test]
579        async fn issue_28407_nesting(cx: &mut TestAppContext) {
580            test_path_likes!(
581                cx,
582                vec![(
583                    path!("/project"),
584                    json!({
585                        "lib": {
586                            "src": {
587                                "main.rs": "",
588                                "only_in_lib.rs": ""
589                            },
590                        },
591                        "src": {
592                            "main.rs": ""
593                        },
594                    }),
595                )],
596                vec![path!("/project")],
597                {
598                    test!("main.rs", "/project/src/main.rs", "/project/src");
599                    test!("main.rs", "/project/lib/src/main.rs", "/project/lib/src");
600
601                    test!("src/main.rs", "/project/src/main.rs", "/project");
602                    test!("src/main.rs", "/project/src/main.rs", "/project/src");
603                    test!("src/main.rs", "/project/lib/src/main.rs", "/project/lib");
604
605                    test!("lib/src/main.rs", "/project/lib/src/main.rs", "/project");
606                    test!(
607                        "lib/src/main.rs",
608                        "/project/lib/src/main.rs",
609                        "/project/src"
610                    );
611                    test!(
612                        "lib/src/main.rs",
613                        "/project/lib/src/main.rs",
614                        "/project/lib"
615                    );
616                    test!(
617                        "lib/src/main.rs",
618                        "/project/lib/src/main.rs",
619                        "/project/lib/src"
620                    );
621                    test!(
622                        "src/only_in_lib.rs",
623                        "/project/lib/src/only_in_lib.rs",
624                        "/project/lib/src",
625                        WorktreeScan
626                    );
627                }
628            )
629        }
630
631        // https://github.com/zed-industries/zed/issues/28339
632        #[gpui::test]
633        async fn issue_28339(cx: &mut TestAppContext) {
634            test_path_likes!(
635                cx,
636                vec![(
637                    path!("/tmp"),
638                    json!({
639                        "issue28339": {
640                            "foo": {
641                                "bar.txt": ""
642                            },
643                        },
644                    }),
645                )],
646                vec![path!("/tmp")],
647                {
648                    test_local!(
649                        "foo/./bar.txt",
650                        "/tmp/issue28339/foo/bar.txt",
651                        "/tmp/issue28339",
652                        WorktreeExact
653                    );
654                    test_local!(
655                        "foo/../foo/bar.txt",
656                        "/tmp/issue28339/foo/bar.txt",
657                        "/tmp/issue28339",
658                        WorktreeExact
659                    );
660                    test_local!(
661                        "foo/..///foo/bar.txt",
662                        "/tmp/issue28339/foo/bar.txt",
663                        "/tmp/issue28339",
664                        WorktreeExact
665                    );
666                    test_local!(
667                        "issue28339/../issue28339/foo/../foo/bar.txt",
668                        "/tmp/issue28339/foo/bar.txt",
669                        "/tmp/issue28339",
670                        WorktreeExact
671                    );
672                    test_local!(
673                        "./bar.txt",
674                        "/tmp/issue28339/foo/bar.txt",
675                        "/tmp/issue28339/foo",
676                        WorktreeExact
677                    );
678                    test_local!(
679                        "../foo/bar.txt",
680                        "/tmp/issue28339/foo/bar.txt",
681                        "/tmp/issue28339/foo",
682                        WorktreeExact
683                    );
684                }
685            )
686        }
687
688        // https://github.com/zed-industries/zed/issues/28339
689        #[gpui::test]
690        async fn issue_28339_remote(cx: &mut TestAppContext) {
691            test_path_likes!(
692                cx,
693                vec![(
694                    path!("/tmp"),
695                    json!({
696                        "issue28339": {
697                            "foo": {
698                                "bar.txt": ""
699                            },
700                        },
701                    }),
702                )],
703                vec![path!("/tmp")],
704                {
705                    test_remote!(
706                        "foo/./bar.txt",
707                        "/tmp/issue28339/foo/bar.txt",
708                        "/tmp/issue28339"
709                    );
710                    test_remote!(
711                        "foo/../foo/bar.txt",
712                        "/tmp/issue28339/foo/bar.txt",
713                        "/tmp/issue28339"
714                    );
715                    test_remote!(
716                        "foo/..///foo/bar.txt",
717                        "/tmp/issue28339/foo/bar.txt",
718                        "/tmp/issue28339"
719                    );
720                    test_remote!(
721                        "issue28339/../issue28339/foo/../foo/bar.txt",
722                        "/tmp/issue28339/foo/bar.txt",
723                        "/tmp/issue28339"
724                    );
725                    test_remote!(
726                        "./bar.txt",
727                        "/tmp/issue28339/foo/bar.txt",
728                        "/tmp/issue28339/foo"
729                    );
730                    test_remote!(
731                        "../foo/bar.txt",
732                        "/tmp/issue28339/foo/bar.txt",
733                        "/tmp/issue28339/foo"
734                    );
735                }
736            )
737        }
738
739        // https://github.com/zed-industries/zed/issues/34027
740        #[gpui::test]
741        async fn issue_34027(cx: &mut TestAppContext) {
742            test_path_likes!(
743                cx,
744                vec![(
745                    path!("/tmp/issue34027"),
746                    json!({
747                        "test.txt": "",
748                        "foo": {
749                            "test.txt": "",
750                        }
751                    }),
752                ),],
753                vec![path!("/tmp/issue34027")],
754                {
755                    test!("test.txt", "/tmp/issue34027/test.txt", "/tmp/issue34027");
756                    test!(
757                        "test.txt",
758                        "/tmp/issue34027/foo/test.txt",
759                        "/tmp/issue34027/foo"
760                    );
761                }
762            )
763        }
764
765        // https://github.com/zed-industries/zed/issues/34027
766        #[gpui::test]
767        async fn issue_34027_siblings(cx: &mut TestAppContext) {
768            test_path_likes!(
769                cx,
770                vec![(
771                    path!("/test"),
772                    json!({
773                        "sub1": {
774                            "file.txt": "",
775                        },
776                        "sub2": {
777                            "file.txt": "",
778                        }
779                    }),
780                ),],
781                vec![path!("/test")],
782                {
783                    test!("file.txt", "/test/sub1/file.txt", "/test/sub1");
784                    test!("file.txt", "/test/sub2/file.txt", "/test/sub2");
785                    test!("sub1/file.txt", "/test/sub1/file.txt", "/test/sub1");
786                    test!("sub2/file.txt", "/test/sub2/file.txt", "/test/sub2");
787                    test!("sub1/file.txt", "/test/sub1/file.txt", "/test/sub2");
788                    test!("sub2/file.txt", "/test/sub2/file.txt", "/test/sub1");
789                }
790            )
791        }
792
793        // https://github.com/zed-industries/zed/issues/34027
794        #[gpui::test]
795        async fn issue_34027_nesting(cx: &mut TestAppContext) {
796            test_path_likes!(
797                cx,
798                vec![(
799                    path!("/test"),
800                    json!({
801                        "sub1": {
802                            "file.txt": "",
803                            "subsub1": {
804                                "file.txt": "",
805                            }
806                        },
807                        "sub2": {
808                            "file.txt": "",
809                            "subsub1": {
810                                "file.txt": "",
811                            }
812                        }
813                    }),
814                ),],
815                vec![path!("/test")],
816                {
817                    test!(
818                        "file.txt",
819                        "/test/sub1/subsub1/file.txt",
820                        "/test/sub1/subsub1"
821                    );
822                    test!(
823                        "file.txt",
824                        "/test/sub2/subsub1/file.txt",
825                        "/test/sub2/subsub1"
826                    );
827                    test!(
828                        "subsub1/file.txt",
829                        "/test/sub1/subsub1/file.txt",
830                        "/test",
831                        WorktreeScan
832                    );
833                    test!(
834                        "subsub1/file.txt",
835                        "/test/sub1/subsub1/file.txt",
836                        "/test",
837                        WorktreeScan
838                    );
839                    test!(
840                        "subsub1/file.txt",
841                        "/test/sub1/subsub1/file.txt",
842                        "/test/sub1"
843                    );
844                    test!(
845                        "subsub1/file.txt",
846                        "/test/sub2/subsub1/file.txt",
847                        "/test/sub2"
848                    );
849                    test!(
850                        "subsub1/file.txt",
851                        "/test/sub1/subsub1/file.txt",
852                        "/test/sub1/subsub1",
853                        WorktreeScan
854                    );
855                }
856            )
857        }
858
859        // https://github.com/zed-industries/zed/issues/34027
860        #[gpui::test]
861        async fn issue_34027_non_worktree_local_file(cx: &mut TestAppContext) {
862            test_path_likes!(
863                cx,
864                vec![
865                    (
866                        path!("/"),
867                        json!({
868                            "file.txt": "",
869                        }),
870                    ),
871                    (
872                        path!("/test"),
873                        json!({
874                            "file.txt": "",
875                        }),
876                    ),
877                ],
878                vec![path!("/test")],
879                {
880                    // Note: Opening a non-worktree file adds that file as a single file worktree.
881                    test_local!("file.txt", "/file.txt", "/", BackgroundPathResolution);
882                }
883            )
884        }
885
886        // https://github.com/zed-industries/zed/issues/34027
887        #[gpui::test]
888        async fn issue_34027_non_worktree_remote_file(cx: &mut TestAppContext) {
889            test_path_likes!(
890                cx,
891                vec![
892                    (
893                        path!("/"),
894                        json!({
895                            "file.txt": "",
896                        }),
897                    ),
898                    (
899                        path!("/test"),
900                        json!({
901                            "file.txt": "",
902                        }),
903                    ),
904                ],
905                vec![path!("/test")],
906                {
907                    // Note: Opening a non-worktree file adds that file as a single file worktree.
908                    test_remote!("file.txt", "/file.txt", "/", BackgroundPathResolution);
909                    test_remote!("/test/file.txt", "/test/file.txt", "/");
910                }
911            )
912        }
913
914        // https://github.com/zed-industries/zed/issues/39159
915        #[gpui::test]
916        async fn issue_39159_remote_absolute_path_outside_worktree(cx: &mut TestAppContext) {
917            test_path_likes!(
918                cx,
919                vec![
920                    (
921                        path!("/tmp"),
922                        json!({
923                            "a.txt": "",
924                        }),
925                    ),
926                    (
927                        path!("/code/project"),
928                        json!({
929                            "src": {
930                                "lib.rs": "",
931                            },
932                        }),
933                    ),
934                ],
935                vec![path!("/code/project")],
936                {
937                    test_remote!(
938                        "/tmp/a.txt",
939                        "/tmp/a.txt",
940                        "/code/project",
941                        BackgroundPathResolution
942                    );
943                }
944            )
945        }
946
947        // See https://github.com/zed-industries/zed/issues/34027
948        #[gpui::test]
949        #[should_panic(expected = "Tooltip mismatch")]
950        async fn issue_34027_gaps(cx: &mut TestAppContext) {
951            test_path_likes!(
952                cx,
953                vec![(
954                    path!("/project"),
955                    json!({
956                        "lib": {
957                            "src": {
958                                "main.rs": ""
959                            },
960                        },
961                        "src": {
962                            "main.rs": ""
963                        },
964                    }),
965                )],
966                vec![path!("/project")],
967                {
968                    test!("main.rs", "/project/src/main.rs", "/project");
969                    test!("main.rs", "/project/lib/src/main.rs", "/project/lib");
970                }
971            )
972        }
973
974        // See https://github.com/zed-industries/zed/issues/34027
975        #[gpui::test]
976        #[should_panic(expected = "Tooltip mismatch")]
977        async fn issue_34027_overlap(cx: &mut TestAppContext) {
978            test_path_likes!(
979                cx,
980                vec![(
981                    path!("/project"),
982                    json!({
983                        "lib": {
984                            "src": {
985                                "main.rs": ""
986                            },
987                        },
988                        "src": {
989                            "main.rs": ""
990                        },
991                    }),
992                )],
993                vec![path!("/project")],
994                {
995                    // Finds "/project/src/main.rs"
996                    test!(
997                        "src/main.rs",
998                        "/project/lib/src/main.rs",
999                        "/project/lib/src"
1000                    );
1001                }
1002            )
1003        }
1004    }
1005}
1006
Served at tenant.openagents/omega Member data and write actions are omitted.