aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/src/roots.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libanalysis/src/roots.rs')
-rw-r--r--crates/libanalysis/src/roots.rs113
1 files changed, 113 insertions, 0 deletions
diff --git a/crates/libanalysis/src/roots.rs b/crates/libanalysis/src/roots.rs
new file mode 100644
index 000000000..675bce54c
--- /dev/null
+++ b/crates/libanalysis/src/roots.rs
@@ -0,0 +1,113 @@
1use std::{
2 collections::HashMap,
3 time::Instant,
4 sync::Arc,
5 panic,
6};
7
8use once_cell::sync::OnceCell;
9use rayon::prelude::*;
10use libeditor::LineIndex;
11use libsyntax2::File;
12
13use {
14 FileId,
15 module_map::{ModuleMap, ChangeKind},
16 symbol_index::FileSymbols,
17};
18
19#[derive(Clone, Default, Debug)]
20pub(crate) struct SourceRoot {
21 file_map: HashMap<FileId, Arc<FileData>>,
22 module_map: ModuleMap,
23}
24
25impl SourceRoot {
26 pub fn update(&mut self, file_id: FileId, text: Option<String>) {
27 let change_kind = if self.file_map.remove(&file_id).is_some() {
28 if text.is_some() {
29 ChangeKind::Update
30 } else {
31 ChangeKind::Delete
32 }
33 } else {
34 ChangeKind::Insert
35 };
36 self.module_map.update_file(file_id, change_kind);
37 self.file_map.remove(&file_id);
38 if let Some(text) = text {
39 let file_data = FileData::new(text);
40 self.file_map.insert(file_id, Arc::new(file_data));
41 } else {
42 self.file_map.remove(&file_id);
43 }
44 }
45 pub fn module_map(&self) -> &ModuleMap {
46 &self.module_map
47 }
48 pub fn lines(&self, file_id: FileId) -> &LineIndex {
49 let data = self.data(file_id);
50 data.lines.get_or_init(|| LineIndex::new(&data.text))
51 }
52 pub fn syntax(&self, file_id: FileId) -> &File {
53 let data = self.data(file_id);
54 let text = &data.text;
55 let syntax = &data.syntax;
56 match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) {
57 Ok(file) => file,
58 Err(err) => {
59 error!("Parser paniced on:\n------\n{}\n------\n", &data.text);
60 panic::resume_unwind(err)
61 }
62 }
63 }
64 pub(crate) fn symbols(&self) -> Vec<(FileId, &FileSymbols)> {
65 self.file_map
66 .iter()
67 .map(|(&file_id, data)| (file_id, data.symbols()))
68 .collect()
69 }
70 pub fn reindex(&self) {
71 let now = Instant::now();
72 self.file_map
73 .par_iter()
74 .for_each(|(_, data)| {
75 data.symbols();
76 });
77 info!("parallel indexing took {:?}", now.elapsed());
78
79 }
80 fn data(&self, file_id: FileId) -> &FileData {
81 match self.file_map.get(&file_id) {
82 Some(data) => data,
83 None => panic!("unknown file: {:?}", file_id),
84 }
85 }
86}
87
88#[derive(Debug)]
89struct FileData {
90 text: String,
91 lines: OnceCell<LineIndex>,
92 syntax: OnceCell<File>,
93 symbols: OnceCell<FileSymbols>,
94}
95
96impl FileData {
97 fn new(text: String) -> FileData {
98 FileData {
99 text,
100 symbols: OnceCell::new(),
101 syntax: OnceCell::new(),
102 lines: OnceCell::new(),
103 }
104 }
105 fn syntax_transient(&self) -> File {
106 self.syntax.get().map(|s| s.clone())
107 .unwrap_or_else(|| File::parse(&self.text))
108 }
109 fn symbols(&self) -> &FileSymbols {
110 let syntax = self.syntax_transient();
111 self.symbols.get_or_init(|| FileSymbols::new(&syntax))
112 }
113}