main.rs

  1use std::sync::Arc;
  2
  3use clap::Parser;
  4use client::{Client, UserStore};
  5use gpui::{AppContext as _, Application};
  6use http_client::FakeHttpClient;
  7use language::LanguageRegistry;
  8use node_runtime::NodeRuntime;
  9use project::{
 10    Project, RealFs,
 11    search::{SearchQuery, SearchResult},
 12};
 13
 14#[derive(Parser)]
 15struct Args {
 16    /// List of worktrees to run the search against.
 17    worktrees: Vec<String>,
 18    #[clap(short)]
 19    query: String,
 20    /// Treat query as a regex.
 21    #[clap(short, long)]
 22    regex: bool,
 23    /// Matches have to be standalone words.
 24    #[clap(long)]
 25    whole_word: bool,
 26    /// Make matching case-sensitive.
 27    #[clap(long, default_value_t = true)]
 28    case_sensitive: bool,
 29    /// Include gitignored files in the search.
 30    #[clap(long)]
 31    include_ignored: bool,
 32}
 33
 34fn main() -> Result<(), anyhow::Error> {
 35    let args = Args::parse();
 36    let query = if args.regex {
 37        SearchQuery::regex(
 38            args.query,
 39            args.whole_word,
 40            args.case_sensitive,
 41            args.include_ignored,
 42            false,
 43            Default::default(),
 44            Default::default(),
 45            false,
 46            None,
 47        )
 48    } else {
 49        SearchQuery::text(
 50            args.query,
 51            args.whole_word,
 52            args.case_sensitive,
 53            args.include_ignored,
 54            Default::default(),
 55            Default::default(),
 56            false,
 57            None,
 58        )
 59    }?;
 60    Application::headless().run(|cx| {
 61        settings::init(cx);
 62        client::init_settings(cx);
 63        language::init(cx);
 64        Project::init_settings(cx);
 65        let client = Client::production(cx);
 66        let http_client = FakeHttpClient::with_200_response();
 67        let (_, rx) = watch::channel(None);
 68        let node = NodeRuntime::new(http_client, None, rx);
 69        let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
 70        let registry = Arc::new(LanguageRegistry::new(cx.background_executor().clone()));
 71        let fs = Arc::new(RealFs::new(None, cx.background_executor().clone()));
 72        let project = Project::local(
 73            client,
 74            node,
 75            user_store,
 76            registry,
 77            fs,
 78            Some(Default::default()),
 79            cx,
 80        );
 81
 82        project.clone().update(cx, move |_, cx| {
 83            cx.spawn(async move |_, cx| {
 84                println!("Loading worktrees");
 85                let worktrees = project.update(cx, |this, cx| {
 86                    args.worktrees
 87                        .into_iter()
 88                        .map(|worktree| this.find_or_create_worktree(worktree, true, cx))
 89                        .collect::<Vec<_>>()
 90                })?;
 91
 92                let worktrees = futures::future::join_all(worktrees)
 93                    .await
 94                    .into_iter()
 95                    .collect::<Result<Vec<_>, anyhow::Error>>()?;
 96
 97                for (worktree, _) in &worktrees {
 98                    worktree
 99                        .update(cx, |this, _| this.as_local().unwrap().scan_complete())?
100                        .await;
101                }
102                println!("Worktrees loaded");
103
104                println!("Starting a project search");
105                let timer = std::time::Instant::now();
106                let mut first_match = None;
107                let matches = project
108                    .update(cx, |this, cx| this.search(query, cx))
109                    .unwrap();
110                let mut matched_files = 0;
111                let mut matched_chunks = 0;
112                while let Ok(match_result) = matches.recv().await {
113                    if first_match.is_none() {
114                        let time = timer.elapsed();
115                        first_match = Some(time);
116                        println!("First match found after {time:?}");
117                    }
118                    if let SearchResult::Buffer { ranges, .. } = match_result {
119                        matched_files += 1;
120                        matched_chunks += ranges.len();
121                    }
122                }
123                let elapsed = timer.elapsed();
124                println!(
125                    "Finished project search after {elapsed:?}. Matched {matched_files} files and {matched_chunks} excerpts"
126                );
127                drop(project);
128                cx.update(|cx| cx.quit())?;
129
130                anyhow::Ok(())
131            })
132            .detach();
133        });
134    });
135    Ok(())
136}