Unnamed repository; edit this file 'description' to name the repository.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use ide_db::{
    base_db::{CrateOrigin, SourceDatabase, SourceDatabaseExt},
    RootDatabase,
};

#[derive(Debug)]
pub struct CrateInfo {
    pub name: String,
    pub version: String,
    pub path: String,
}

pub(crate) fn fetch_crates(db: &RootDatabase) -> Vec<CrateInfo> {
    let crate_graph = db.crate_graph();
    crate_graph
        .iter()
        .map(|crate_id| &crate_graph[crate_id])
        .filter(|&data| !matches!(data.origin, CrateOrigin::Local { .. }))
        .map(|data| {
            let crate_name = crate_name(data);
            let version = data.version.clone().unwrap_or_else(|| "".to_owned());
            let crate_path = crate_path(db, data, &crate_name);

            CrateInfo { name: crate_name, version, path: crate_path }
        })
        .collect()
}

fn crate_name(data: &ide_db::base_db::CrateData) -> String {
    data.display_name
        .clone()
        .map(|it| it.canonical_name().to_owned())
        .unwrap_or("unknown".to_string())
}

fn crate_path(db: &RootDatabase, data: &ide_db::base_db::CrateData, crate_name: &str) -> String {
    let source_root_id = db.file_source_root(data.root_file_id);
    let source_root = db.source_root(source_root_id);
    let source_root_path = source_root.path_for_file(&data.root_file_id);
    match source_root_path.cloned() {
        Some(mut root_path) => {
            let mut crate_path = "".to_string();
            while let Some(vfs_path) = root_path.parent() {
                match vfs_path.name_and_extension() {
                    Some((name, _)) => {
                        if name.starts_with(crate_name) {
                            crate_path = vfs_path.to_string();
                            break;
                        }
                    }
                    None => break,
                }
                root_path = vfs_path;
            }
            crate_path
        }
        None => "".to_owned(),
    }
}