diff options
author | Aleksey Kladov <[email protected]> | 2018-08-10 13:07:43 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-10 13:07:43 +0100 |
commit | d7c5a6f3081c2e7266620779d3c32067f947b959 (patch) | |
tree | 2aefb594e062c8fa7cc7879e5df6883f3bc5d015 /libanalysis/src/lib.rs | |
parent | 4a900fd6815d3ea722b5e664aee9eac8bb9cb14f (diff) |
Start lang server
Diffstat (limited to 'libanalysis/src/lib.rs')
-rw-r--r-- | libanalysis/src/lib.rs | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/libanalysis/src/lib.rs b/libanalysis/src/lib.rs new file mode 100644 index 000000000..07e7d567d --- /dev/null +++ b/libanalysis/src/lib.rs | |||
@@ -0,0 +1,107 @@ | |||
1 | extern crate failure; | ||
2 | extern crate libsyntax2; | ||
3 | extern crate parking_lot; | ||
4 | |||
5 | use std::{ | ||
6 | fs, | ||
7 | sync::Arc, | ||
8 | collections::hash_map::HashMap, | ||
9 | path::{PathBuf, Path}, | ||
10 | }; | ||
11 | use parking_lot::RwLock; | ||
12 | use libsyntax2::ast; | ||
13 | |||
14 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | ||
15 | |||
16 | pub struct WorldState { | ||
17 | data: Arc<WorldData> | ||
18 | } | ||
19 | |||
20 | pub struct World { | ||
21 | data: Arc<WorldData>, | ||
22 | } | ||
23 | |||
24 | impl WorldState { | ||
25 | pub fn new() -> WorldState { | ||
26 | WorldState { | ||
27 | data: Arc::new(WorldData::default()) | ||
28 | } | ||
29 | } | ||
30 | |||
31 | pub fn snapshot(&self) -> World { | ||
32 | World { data: self.data.clone() } | ||
33 | } | ||
34 | |||
35 | pub fn change_overlay(&mut self, path: PathBuf, text: Option<String>) { | ||
36 | let data = self.data_mut(); | ||
37 | data.file_map.get_mut().remove(&path); | ||
38 | data.fs_map.get_mut().remove(&path); | ||
39 | if let Some(text) = text { | ||
40 | data.mem_map.insert(path, Arc::new(text)); | ||
41 | } else { | ||
42 | data.mem_map.remove(&path); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | fn data_mut(&mut self) -> &mut WorldData { | ||
47 | if Arc::get_mut(&mut self.data).is_none() { | ||
48 | let fs_map = self.data.fs_map.read().clone(); | ||
49 | let file_map = self.data.file_map.read().clone(); | ||
50 | self.data = Arc::new(WorldData { | ||
51 | mem_map: self.data.mem_map.clone(), | ||
52 | fs_map: RwLock::new(fs_map), | ||
53 | file_map: RwLock::new(file_map), | ||
54 | }); | ||
55 | } | ||
56 | Arc::get_mut(&mut self.data).unwrap() | ||
57 | } | ||
58 | } | ||
59 | |||
60 | |||
61 | impl World { | ||
62 | pub fn file_syntax(&self, path: &Path) -> Result<ast::File> { | ||
63 | { | ||
64 | let guard = self.data.file_map.read(); | ||
65 | if let Some(file) = guard.get(path) { | ||
66 | return Ok(file.clone()); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | let file = self.with_file_text(path, ast::File::parse)?; | ||
71 | let mut guard = self.data.file_map.write(); | ||
72 | let file = guard.entry(path.to_owned()) | ||
73 | .or_insert(file) | ||
74 | .clone(); | ||
75 | Ok(file) | ||
76 | } | ||
77 | |||
78 | fn with_file_text<F: FnOnce(&str) -> R, R>(&self, path: &Path, f: F) -> Result<R> { | ||
79 | if let Some(text) = self.data.mem_map.get(path) { | ||
80 | return Ok(f(&*text)); | ||
81 | } | ||
82 | |||
83 | { | ||
84 | let guard = self.data.fs_map.read(); | ||
85 | if let Some(text) = guard.get(path) { | ||
86 | return Ok(f(&*text)); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | let text = fs::read_to_string(path)?; | ||
91 | { | ||
92 | let mut guard = self.data.fs_map.write(); | ||
93 | guard.entry(path.to_owned()) | ||
94 | .or_insert_with(|| Arc::new(text)); | ||
95 | } | ||
96 | let guard = self.data.fs_map.read(); | ||
97 | Ok(f(&guard[path])) | ||
98 | } | ||
99 | } | ||
100 | |||
101 | |||
102 | #[derive(Default)] | ||
103 | struct WorldData { | ||
104 | mem_map: HashMap<PathBuf, Arc<String>>, | ||
105 | fs_map: RwLock<HashMap<PathBuf, Arc<String>>>, | ||
106 | file_map: RwLock<HashMap<PathBuf, ast::File>>, | ||
107 | } | ||