diff options
Diffstat (limited to 'crates/libanalysis/src/lib.rs')
-rw-r--r-- | crates/libanalysis/src/lib.rs | 78 |
1 files changed, 32 insertions, 46 deletions
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index 74f043a9b..e4df3de2e 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -1,3 +1,4 @@ | |||
1 | #[macro_use] | ||
1 | extern crate failure; | 2 | extern crate failure; |
2 | extern crate parking_lot; | 3 | extern crate parking_lot; |
3 | #[macro_use] | 4 | #[macro_use] |
@@ -9,12 +10,10 @@ extern crate libeditor; | |||
9 | use once_cell::sync::OnceCell; | 10 | use once_cell::sync::OnceCell; |
10 | 11 | ||
11 | use std::{ | 12 | use std::{ |
12 | fs, | ||
13 | sync::Arc, | 13 | sync::Arc, |
14 | collections::hash_map::HashMap, | 14 | collections::hash_map::HashMap, |
15 | path::{PathBuf, Path}, | 15 | path::{PathBuf, Path}, |
16 | }; | 16 | }; |
17 | use parking_lot::RwLock; | ||
18 | use libsyntax2::ast; | 17 | use libsyntax2::ast; |
19 | use libeditor::LineIndex; | 18 | use libeditor::LineIndex; |
20 | 19 | ||
@@ -40,22 +39,27 @@ impl WorldState { | |||
40 | World { data: self.data.clone() } | 39 | World { data: self.data.clone() } |
41 | } | 40 | } |
42 | 41 | ||
43 | pub fn change_overlay(&mut self, path: PathBuf, text: Option<String>) { | 42 | pub fn change_file(&mut self, path: PathBuf, text: Option<String>) { |
43 | self.change_files(::std::iter::once((path, text))); | ||
44 | } | ||
45 | |||
46 | pub fn change_files(&mut self, changes: impl Iterator<Item=(PathBuf, Option<String>)>) { | ||
44 | let data = self.data_mut(); | 47 | let data = self.data_mut(); |
45 | data.file_map.get_mut().remove(&path); | 48 | for (path, text) in changes { |
46 | if let Some(text) = text { | 49 | data.file_map.remove(&path); |
47 | data.mem_map.insert(path, Arc::new(text)); | 50 | if let Some(text) = text { |
48 | } else { | 51 | let file_data = FileData::new(text); |
49 | data.mem_map.remove(&path); | 52 | data.file_map.insert(path, Arc::new(file_data)); |
53 | } else { | ||
54 | data.file_map.remove(&path); | ||
55 | } | ||
50 | } | 56 | } |
51 | } | 57 | } |
52 | 58 | ||
53 | fn data_mut(&mut self) -> &mut WorldData { | 59 | fn data_mut(&mut self) -> &mut WorldData { |
54 | if Arc::get_mut(&mut self.data).is_none() { | 60 | if Arc::get_mut(&mut self.data).is_none() { |
55 | let file_map = self.data.file_map.read().clone(); | ||
56 | self.data = Arc::new(WorldData { | 61 | self.data = Arc::new(WorldData { |
57 | mem_map: self.data.mem_map.clone(), | 62 | file_map: self.data.file_map.clone(), |
58 | file_map: RwLock::new(file_map), | ||
59 | }); | 63 | }); |
60 | } | 64 | } |
61 | Arc::get_mut(&mut self.data).unwrap() | 65 | Arc::get_mut(&mut self.data).unwrap() |
@@ -69,7 +73,7 @@ impl World { | |||
69 | let syntax = data.syntax | 73 | let syntax = data.syntax |
70 | .get_or_init(|| { | 74 | .get_or_init(|| { |
71 | trace!("parsing: {}", path.display()); | 75 | trace!("parsing: {}", path.display()); |
72 | ast::File::parse(self.file_text(path, &data)) | 76 | ast::File::parse(&data.text) |
73 | }).clone(); | 77 | }).clone(); |
74 | Ok(syntax) | 78 | Ok(syntax) |
75 | } | 79 | } |
@@ -79,56 +83,38 @@ impl World { | |||
79 | let index = data.lines | 83 | let index = data.lines |
80 | .get_or_init(|| { | 84 | .get_or_init(|| { |
81 | trace!("calc line index: {}", path.display()); | 85 | trace!("calc line index: {}", path.display()); |
82 | LineIndex::new(self.file_text(path, &data)) | 86 | LineIndex::new(&data.text) |
83 | }); | 87 | }); |
84 | Ok(index.clone()) | 88 | Ok(index.clone()) |
85 | } | 89 | } |
86 | 90 | ||
87 | fn file_text<'a>(&'a self, path: &Path, file_data: &'a FileData) -> &'a str { | ||
88 | match file_data.text.as_ref() { | ||
89 | Some(text) => text.as_str(), | ||
90 | None => self.data.mem_map[path].as_str() | ||
91 | } | ||
92 | } | ||
93 | |||
94 | fn file_data(&self, path: &Path) -> Result<Arc<FileData>> { | 91 | fn file_data(&self, path: &Path) -> Result<Arc<FileData>> { |
95 | { | 92 | match self.data.file_map.get(path) { |
96 | let guard = self.data.file_map.read(); | 93 | Some(data) => Ok(data.clone()), |
97 | if let Some(data) = guard.get(path) { | 94 | None => bail!("unknown file: {}", path.display()), |
98 | return Ok(data.clone()); | ||
99 | } | ||
100 | } | 95 | } |
101 | |||
102 | let text = if self.data.mem_map.contains_key(path) { | ||
103 | None | ||
104 | } else { | ||
105 | trace!("loading file from disk: {}", path.display()); | ||
106 | Some(fs::read_to_string(path)?) | ||
107 | }; | ||
108 | let res = { | ||
109 | let mut guard = self.data.file_map.write(); | ||
110 | guard.entry(path.to_owned()) | ||
111 | .or_insert_with(|| Arc::new(FileData { | ||
112 | text, | ||
113 | syntax: OnceCell::new(), | ||
114 | lines: OnceCell::new(), | ||
115 | })) | ||
116 | .clone() | ||
117 | }; | ||
118 | Ok(res) | ||
119 | } | 96 | } |
120 | } | 97 | } |
121 | 98 | ||
122 | 99 | ||
123 | #[derive(Default, Debug)] | 100 | #[derive(Default, Debug)] |
124 | struct WorldData { | 101 | struct WorldData { |
125 | mem_map: HashMap<PathBuf, Arc<String>>, | 102 | file_map: HashMap<PathBuf, Arc<FileData>>, |
126 | file_map: RwLock<HashMap<PathBuf, Arc<FileData>>>, | ||
127 | } | 103 | } |
128 | 104 | ||
129 | #[derive(Debug)] | 105 | #[derive(Debug)] |
130 | struct FileData { | 106 | struct FileData { |
131 | text: Option<String>, | 107 | text: String, |
132 | syntax: OnceCell<ast::File>, | 108 | syntax: OnceCell<ast::File>, |
133 | lines: OnceCell<LineIndex>, | 109 | lines: OnceCell<LineIndex>, |
134 | } | 110 | } |
111 | |||
112 | impl FileData { | ||
113 | fn new(text: String) -> FileData { | ||
114 | FileData { | ||
115 | text, | ||
116 | syntax: OnceCell::new(), | ||
117 | lines: OnceCell::new(), | ||
118 | } | ||
119 | } | ||
120 | } | ||