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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#[cfg(test)]
#[path = "db_test.rs"]
mod test;
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use std::sync::Arc;
use cairo_lang_project::ProjectConfig;
use cairo_lang_utils::Upcast;
use crate::detect::detect_corelib;
use crate::ids::{CrateId, CrateLongId, Directory, FileId, FileLongId};
use crate::span::{FileSummary, TextOffset};
#[salsa::query_group(FilesDatabase)]
pub trait FilesGroup {
#[salsa::interned]
fn intern_crate(&self, crt: CrateLongId) -> CrateId;
#[salsa::interned]
fn intern_file(&self, file: FileLongId) -> FileId;
#[salsa::input]
fn crate_roots(&self) -> Arc<HashMap<CrateId, Directory>>;
#[salsa::input]
fn file_overrides(&self) -> Arc<HashMap<FileId, Arc<String>>>;
fn crates(&self) -> Vec<CrateId>;
fn crate_root_dir(&self, crate_id: CrateId) -> Option<Directory>;
fn priv_raw_file_content(&self, file_id: FileId) -> Option<Arc<String>>;
fn file_content(&self, file_id: FileId) -> Option<Arc<String>>;
fn file_summary(&self, file_id: FileId) -> Option<Arc<FileSummary>>;
}
pub fn init_files_group(db: &mut (dyn FilesGroup + 'static)) {
db.set_file_overrides(Arc::new(HashMap::new()));
db.set_crate_roots(Arc::new(HashMap::new()));
let core_crate = db.intern_crate(CrateLongId("core".into()));
let path = detect_corelib();
let core_root_dir = Directory(path);
db.set_crate_root(core_crate, Some(core_root_dir));
}
impl AsFilesGroupMut for dyn FilesGroup {
fn as_files_group_mut(&mut self) -> &mut (dyn FilesGroup + 'static) {
self
}
}
pub trait FilesGroupEx: Upcast<dyn FilesGroup> + AsFilesGroupMut {
fn override_file_content(&mut self, file: FileId, content: Option<Arc<String>>) {
let mut overrides = Upcast::upcast(self).file_overrides().as_ref().clone();
match content {
Some(content) => overrides.insert(file, content),
None => overrides.remove(&file),
};
self.as_files_group_mut().set_file_overrides(Arc::new(overrides));
}
fn set_crate_root(&mut self, crt: CrateId, root: Option<Directory>) {
let mut crate_roots = Upcast::upcast(self).crate_roots().as_ref().clone();
match root {
Some(root) => crate_roots.insert(crt, root),
None => crate_roots.remove(&crt),
};
self.as_files_group_mut().set_crate_roots(Arc::new(crate_roots));
}
fn with_project_config(&mut self, config: ProjectConfig) {
for (crate_name, directory_path) in config.content.crate_roots {
let crate_id = Upcast::upcast(self).intern_crate(CrateLongId(crate_name));
let mut path = PathBuf::from(&directory_path);
if path.is_relative() {
path = PathBuf::from(&config.base_path).join(path);
}
let root = Directory(path);
self.set_crate_root(crate_id, Some(root));
}
}
}
impl<T: Upcast<dyn FilesGroup> + AsFilesGroupMut + ?Sized> FilesGroupEx for T {}
pub trait AsFilesGroupMut {
fn as_files_group_mut(&mut self) -> &mut (dyn FilesGroup + 'static);
}
fn crates(db: &dyn FilesGroup) -> Vec<CrateId> {
db.crate_roots().keys().copied().collect()
}
fn crate_root_dir(db: &dyn FilesGroup, crt: CrateId) -> Option<Directory> {
db.crate_roots().get(&crt).cloned()
}
fn priv_raw_file_content(db: &dyn FilesGroup, file: FileId) -> Option<Arc<String>> {
match db.lookup_intern_file(file) {
FileLongId::OnDisk(path) => match fs::read_to_string(path) {
Ok(content) => Some(Arc::new(content)),
Err(_) => None,
},
FileLongId::Virtual(virt) => Some(virt.content),
}
}
fn file_content(db: &dyn FilesGroup, file: FileId) -> Option<Arc<String>> {
let overrides = db.file_overrides();
overrides.get(&file).cloned().or_else(|| db.priv_raw_file_content(file))
}
fn file_summary(db: &dyn FilesGroup, file: FileId) -> Option<Arc<FileSummary>> {
let content = db.file_content(file)?;
let mut line_offsets = vec![TextOffset(0)];
let mut offset = 0;
for ch in content.chars() {
offset += 1;
if ch == '\n' {
line_offsets.push(TextOffset(offset));
}
}
Some(Arc::new(FileSummary { line_offsets, total_length: offset }))
}