1 //! Loads a Cargo project into a static instance of analysis, without support
2 //! for incorporating changes.
3 use std::{path::Path, sync::Arc};
6 use crossbeam_channel::{unbounded, Receiver};
7 use ra_db::{AbsPathBuf, CrateGraph};
8 use ra_ide::{AnalysisChange, AnalysisHost};
9 use ra_project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace};
10 use vfs::{loader::Handle, AbsPath};
12 use crate::global_state::{ProjectFolders, SourceRootConfig};
16 load_out_dirs_from_check: bool,
17 with_proc_macro: bool,
18 ) -> Result<(AnalysisHost, vfs::Vfs)> {
19 let root = AbsPathBuf::assert(std::env::current_dir()?.join(root));
20 let root = ProjectManifest::discover_single(&root)?;
21 let ws = ProjectWorkspace::load(
23 &CargoConfig { load_out_dirs_from_check, ..Default::default() },
27 let (sender, receiver) = unbounded();
28 let mut vfs = vfs::Vfs::default();
31 vfs_notify::LoaderHandle::spawn(Box::new(move |msg| sender.send(msg).unwrap()));
35 let proc_macro_client = if with_proc_macro {
36 let path = std::env::current_exe()?;
37 ProcMacroClient::extern_process(path, &["proc-macro"]).unwrap()
39 ProcMacroClient::dummy()
42 let crate_graph = ws.to_crate_graph(None, &proc_macro_client, &mut |path: &AbsPath| {
43 let contents = loader.load_sync(path);
44 let path = vfs::VfsPath::from(path.to_path_buf());
45 vfs.set_file_contents(path.clone(), contents);
49 let project_folders = ProjectFolders::new(&[ws]);
50 loader.set_config(vfs::loader::Config { load: project_folders.load, watch: vec![] });
52 log::debug!("crate graph: {:?}", crate_graph);
53 let host = load(crate_graph, project_folders.source_root_config, &mut vfs, &receiver);
58 crate_graph: CrateGraph,
59 source_root_config: SourceRootConfig,
61 receiver: &Receiver<vfs::loader::Message>,
63 let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
64 let mut host = AnalysisHost::new(lru_cap);
65 let mut analysis_change = AnalysisChange::new();
67 // wait until Vfs has loaded all roots
68 for task in receiver {
70 vfs::loader::Message::Progress { n_done, n_total } => {
71 if n_done == n_total {
75 vfs::loader::Message::Loaded { files } => {
76 for (path, contents) in files {
77 vfs.set_file_contents(path.into(), contents)
82 let changes = vfs.take_changes();
85 let contents = vfs.file_contents(file.file_id).to_vec();
86 if let Ok(text) = String::from_utf8(contents) {
87 analysis_change.change_file(file.file_id, Some(Arc::new(text)))
91 let source_roots = source_root_config.partition(&vfs);
92 analysis_change.set_roots(source_roots);
94 analysis_change.set_crate_graph(crate_graph);
96 host.apply_change(analysis_change);
107 fn test_loading_rust_analyzer() {
108 let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
109 let (host, _vfs) = load_cargo(path, false, false).unwrap();
110 let n_crates = Crate::all(host.raw_database()).len();
111 // RA has quite a few crates, but the exact count doesn't matter
112 assert!(n_crates > 20);