project_search.rs

  1use std::{path::Path, sync::Arc};
  2
  3use crate::init_test;
  4use fs::FakeFs;
  5use project::{Project, ProjectEntryId, project_search::PathInclusionMatcher, search::SearchQuery};
  6use serde_json::json;
  7use settings::Settings;
  8use util::{
  9    path,
 10    paths::{PathMatcher, PathStyle},
 11    rel_path::RelPath,
 12};
 13use worktree::{Entry, EntryKind, WorktreeSettings};
 14
 15#[gpui::test]
 16async fn test_path_inclusion_matcher(cx: &mut gpui::TestAppContext) {
 17    init_test(cx);
 18
 19    let fs = FakeFs::new(cx.background_executor.clone());
 20    fs.insert_tree(
 21        "/root",
 22        json!({
 23            ".gitignore": "src/data/\n",
 24            "src": {
 25                "data": {
 26                    "main.csv": "field_1,field_2,field_3",
 27                },
 28                "lib": {
 29                    "main.txt": "Are you familiar with fields?",
 30                },
 31            },
 32        }),
 33    )
 34    .await;
 35
 36    let project = Project::test(fs.clone(), [path!("/root").as_ref()], cx).await;
 37    let worktree = project.update(cx, |project, cx| project.worktrees(cx).next().unwrap());
 38    let (worktree_settings, worktree_snapshot) = worktree.update(cx, |worktree, cx| {
 39        let settings_location = worktree.settings_location(cx);
 40        return (
 41            WorktreeSettings::get(Some(settings_location), cx).clone(),
 42            worktree.snapshot(),
 43        );
 44    });
 45
 46    // Manually create a test entry for the gitignored directory since it won't
 47    // be loaded by the worktree
 48    let entry = Entry {
 49        id: ProjectEntryId::from_proto(1),
 50        kind: EntryKind::UnloadedDir,
 51        path: Arc::from(RelPath::unix(Path::new("src/data")).unwrap()),
 52        inode: 0,
 53        mtime: None,
 54        canonical_path: None,
 55        is_ignored: true,
 56        is_hidden: false,
 57        is_always_included: false,
 58        is_external: false,
 59        is_private: false,
 60        size: 0,
 61        char_bag: Default::default(),
 62        is_fifo: false,
 63    };
 64
 65    // 1. Test searching for `field`, including ignored files without any
 66    // inclusion and exclusion filters.
 67    let include_ignored = true;
 68    let files_to_include = PathMatcher::default();
 69    let files_to_exclude = PathMatcher::default();
 70    let match_full_paths = false;
 71    let search_query = SearchQuery::text(
 72        "field",
 73        false,
 74        false,
 75        include_ignored,
 76        files_to_include,
 77        files_to_exclude,
 78        match_full_paths,
 79        None,
 80    )
 81    .unwrap();
 82
 83    let path_matcher = PathInclusionMatcher::new(Arc::new(search_query));
 84    assert!(path_matcher.should_scan_gitignored_dir(
 85        &entry,
 86        &worktree_snapshot,
 87        &worktree_settings
 88    ));
 89
 90    // 2. Test searching for `field`, including ignored files but updating
 91    // `files_to_include` to only include files under `src/lib`.
 92    let include_ignored = true;
 93    let files_to_include = PathMatcher::new(vec!["src/lib"], PathStyle::Posix).unwrap();
 94    let files_to_exclude = PathMatcher::default();
 95    let match_full_paths = false;
 96    let search_query = SearchQuery::text(
 97        "field",
 98        false,
 99        false,
100        include_ignored,
101        files_to_include,
102        files_to_exclude,
103        match_full_paths,
104        None,
105    )
106    .unwrap();
107
108    let path_matcher = PathInclusionMatcher::new(Arc::new(search_query));
109    assert!(!path_matcher.should_scan_gitignored_dir(
110        &entry,
111        &worktree_snapshot,
112        &worktree_settings
113    ));
114}