diff options
-rw-r--r-- | code/src/extension.ts | 2 | ||||
-rw-r--r-- | crates/libanalysis/src/api.rs | 35 | ||||
-rw-r--r-- | crates/libanalysis/src/imp.rs | 58 | ||||
-rw-r--r-- | crates/libanalysis/src/lib.rs | 86 | ||||
-rw-r--r-- | crates/server/src/server_world.rs | 16 |
5 files changed, 101 insertions, 96 deletions
diff --git a/code/src/extension.ts b/code/src/extension.ts index f2589ef2f..53ef83aab 100644 --- a/code/src/extension.ts +++ b/code/src/extension.ts | |||
@@ -395,7 +395,7 @@ async function applySourceChange(change: SourceChange) { | |||
395 | let uri = client.protocol2CodeConverter.asUri(toReveal.textDocument.uri) | 395 | let uri = client.protocol2CodeConverter.asUri(toReveal.textDocument.uri) |
396 | let position = client.protocol2CodeConverter.asPosition(toReveal.position) | 396 | let position = client.protocol2CodeConverter.asPosition(toReveal.position) |
397 | let editor = vscode.window.activeTextEditor; | 397 | let editor = vscode.window.activeTextEditor; |
398 | if (!editor || editor.document.uri != uri) return | 398 | if (!editor || editor.document.uri.toString() != uri.toString()) return |
399 | if (!editor.selection.isEmpty) return | 399 | if (!editor.selection.isEmpty) return |
400 | editor!.selection = new vscode.Selection(position, position) | 400 | editor!.selection = new vscode.Selection(position, position) |
401 | } | 401 | } |
diff --git a/crates/libanalysis/src/api.rs b/crates/libanalysis/src/api.rs index 02eaf7b1c..ded88cd15 100644 --- a/crates/libanalysis/src/api.rs +++ b/crates/libanalysis/src/api.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use relative_path::RelativePathBuf; | 1 | use relative_path::{RelativePath, RelativePathBuf}; |
2 | use libsyntax2::{File, TextRange, TextUnit, AtomEdit}; | 2 | use libsyntax2::{File, TextRange, TextUnit, AtomEdit}; |
3 | use libeditor; | 3 | use libeditor; |
4 | use {imp::AnalysisImpl, FileId, Query}; | 4 | use {imp::{AnalysisImpl, AnalysisHostImpl}, Query}; |
5 | 5 | ||
6 | pub use libeditor::{ | 6 | pub use libeditor::{ |
7 | LocalEdit, StructureNode, LineIndex, FileSymbol, | 7 | LocalEdit, StructureNode, LineIndex, FileSymbol, |
@@ -109,3 +109,34 @@ impl Analysis { | |||
109 | self.imp.diagnostics(file_id) | 109 | self.imp.diagnostics(file_id) |
110 | } | 110 | } |
111 | } | 111 | } |
112 | |||
113 | pub trait FileResolver: Send + Sync + 'static { | ||
114 | fn file_stem(&self, id: FileId) -> String; | ||
115 | fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>; | ||
116 | } | ||
117 | |||
118 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
119 | pub struct FileId(pub u32); | ||
120 | |||
121 | #[derive(Debug)] | ||
122 | pub struct AnalysisHost { | ||
123 | pub(crate) imp: AnalysisHostImpl | ||
124 | } | ||
125 | |||
126 | impl AnalysisHost { | ||
127 | pub fn new() -> AnalysisHost { | ||
128 | AnalysisHost { imp: AnalysisHostImpl::new() } | ||
129 | } | ||
130 | |||
131 | pub fn analysis(&self, file_resolver: impl FileResolver) -> Analysis { | ||
132 | Analysis { imp: self.imp.analysis(file_resolver) } | ||
133 | } | ||
134 | |||
135 | pub fn change_file(&mut self, file_id: FileId, text: Option<String>) { | ||
136 | self.change_files(::std::iter::once((file_id, text))); | ||
137 | } | ||
138 | |||
139 | pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) { | ||
140 | self.imp.change_files(changes) | ||
141 | } | ||
142 | } | ||
diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs index 5f451f53f..06bbc7cf2 100644 --- a/crates/libanalysis/src/imp.rs +++ b/crates/libanalysis/src/imp.rs | |||
@@ -22,9 +22,65 @@ use { | |||
22 | FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, | 22 | FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, |
23 | module_map::Problem, | 23 | module_map::Problem, |
24 | symbol_index::FileSymbols, | 24 | symbol_index::FileSymbols, |
25 | module_map::ModuleMap, | 25 | module_map::{ModuleMap, ChangeKind}, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | #[derive(Debug)] | ||
29 | pub(crate) struct AnalysisHostImpl { | ||
30 | data: Arc<WorldData> | ||
31 | } | ||
32 | |||
33 | impl AnalysisHostImpl { | ||
34 | pub fn new() -> AnalysisHostImpl { | ||
35 | AnalysisHostImpl { | ||
36 | data: Arc::new(WorldData::default()), | ||
37 | } | ||
38 | } | ||
39 | |||
40 | pub fn analysis( | ||
41 | &self, | ||
42 | file_resolver: impl FileResolver, | ||
43 | ) -> AnalysisImpl { | ||
44 | AnalysisImpl { | ||
45 | needs_reindex: AtomicBool::new(false), | ||
46 | file_resolver: Arc::new(file_resolver), | ||
47 | data: self.data.clone() | ||
48 | } | ||
49 | } | ||
50 | |||
51 | pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) { | ||
52 | let data = self.data_mut(); | ||
53 | for (file_id, text) in changes { | ||
54 | let change_kind = if data.file_map.remove(&file_id).is_some() { | ||
55 | if text.is_some() { | ||
56 | ChangeKind::Update | ||
57 | } else { | ||
58 | ChangeKind::Delete | ||
59 | } | ||
60 | } else { | ||
61 | ChangeKind::Insert | ||
62 | }; | ||
63 | data.module_map.update_file(file_id, change_kind); | ||
64 | data.file_map.remove(&file_id); | ||
65 | if let Some(text) = text { | ||
66 | let file_data = FileData::new(text); | ||
67 | data.file_map.insert(file_id, Arc::new(file_data)); | ||
68 | } else { | ||
69 | data.file_map.remove(&file_id); | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | fn data_mut(&mut self) -> &mut WorldData { | ||
75 | if Arc::get_mut(&mut self.data).is_none() { | ||
76 | self.data = Arc::new(WorldData { | ||
77 | file_map: self.data.file_map.clone(), | ||
78 | module_map: self.data.module_map.clone(), | ||
79 | }); | ||
80 | } | ||
81 | Arc::get_mut(&mut self.data).unwrap() | ||
82 | } | ||
83 | } | ||
28 | 84 | ||
29 | pub(crate) struct AnalysisImpl { | 85 | pub(crate) struct AnalysisImpl { |
30 | pub(crate) needs_reindex: AtomicBool, | 86 | pub(crate) needs_reindex: AtomicBool, |
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index 027d7439b..a39141941 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -14,92 +14,10 @@ mod module_map; | |||
14 | mod api; | 14 | mod api; |
15 | mod imp; | 15 | mod imp; |
16 | 16 | ||
17 | use std::{ | ||
18 | sync::{ | ||
19 | Arc, | ||
20 | atomic::{AtomicBool}, | ||
21 | }, | ||
22 | }; | ||
23 | |||
24 | use relative_path::RelativePath; | ||
25 | |||
26 | use self::{ | ||
27 | module_map::{ChangeKind}, | ||
28 | imp::{WorldData, FileData}, | ||
29 | }; | ||
30 | pub use self::symbol_index::Query; | 17 | pub use self::symbol_index::Query; |
31 | pub use self::api::{ | 18 | pub use self::api::{ |
32 | Analysis, SourceChange, SourceFileEdit, FileSystemEdit, Position, Diagnostic, Runnable, RunnableKind | 19 | AnalysisHost, Analysis, SourceChange, SourceFileEdit, FileSystemEdit, Position, Diagnostic, Runnable, RunnableKind, |
20 | FileId, FileResolver, | ||
33 | }; | 21 | }; |
34 | 22 | ||
35 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | 23 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; |
36 | |||
37 | pub trait FileResolver: Send + Sync + 'static { | ||
38 | fn file_stem(&self, id: FileId) -> String; | ||
39 | fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>; | ||
40 | } | ||
41 | |||
42 | #[derive(Debug)] | ||
43 | pub struct WorldState { | ||
44 | data: Arc<WorldData> | ||
45 | } | ||
46 | |||
47 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
48 | pub struct FileId(pub u32); | ||
49 | |||
50 | impl WorldState { | ||
51 | pub fn new() -> WorldState { | ||
52 | WorldState { | ||
53 | data: Arc::new(WorldData::default()), | ||
54 | } | ||
55 | } | ||
56 | |||
57 | pub fn analysis( | ||
58 | &self, | ||
59 | file_resolver: impl FileResolver, | ||
60 | ) -> Analysis { | ||
61 | let imp = imp::AnalysisImpl { | ||
62 | needs_reindex: AtomicBool::new(false), | ||
63 | file_resolver: Arc::new(file_resolver), | ||
64 | data: self.data.clone() | ||
65 | }; | ||
66 | Analysis { imp } | ||
67 | } | ||
68 | |||
69 | pub fn change_file(&mut self, file_id: FileId, text: Option<String>) { | ||
70 | self.change_files(::std::iter::once((file_id, text))); | ||
71 | } | ||
72 | |||
73 | pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) { | ||
74 | let data = self.data_mut(); | ||
75 | for (file_id, text) in changes { | ||
76 | let change_kind = if data.file_map.remove(&file_id).is_some() { | ||
77 | if text.is_some() { | ||
78 | ChangeKind::Update | ||
79 | } else { | ||
80 | ChangeKind::Delete | ||
81 | } | ||
82 | } else { | ||
83 | ChangeKind::Insert | ||
84 | }; | ||
85 | data.module_map.update_file(file_id, change_kind); | ||
86 | data.file_map.remove(&file_id); | ||
87 | if let Some(text) = text { | ||
88 | let file_data = FileData::new(text); | ||
89 | data.file_map.insert(file_id, Arc::new(file_data)); | ||
90 | } else { | ||
91 | data.file_map.remove(&file_id); | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | |||
96 | fn data_mut(&mut self) -> &mut WorldData { | ||
97 | if Arc::get_mut(&mut self.data).is_none() { | ||
98 | self.data = Arc::new(WorldData { | ||
99 | file_map: self.data.file_map.clone(), | ||
100 | module_map: self.data.module_map.clone(), | ||
101 | }); | ||
102 | } | ||
103 | Arc::get_mut(&mut self.data).unwrap() | ||
104 | } | ||
105 | } | ||
diff --git a/crates/server/src/server_world.rs b/crates/server/src/server_world.rs index 6c85914ba..9ba7df0b8 100644 --- a/crates/server/src/server_world.rs +++ b/crates/server/src/server_world.rs | |||
@@ -5,7 +5,7 @@ use std::{ | |||
5 | }; | 5 | }; |
6 | 6 | ||
7 | use languageserver_types::Url; | 7 | use languageserver_types::Url; |
8 | use libanalysis::{FileId, WorldState, Analysis}; | 8 | use libanalysis::{FileId, AnalysisHost, Analysis}; |
9 | 9 | ||
10 | use { | 10 | use { |
11 | Result, | 11 | Result, |
@@ -15,7 +15,7 @@ use { | |||
15 | 15 | ||
16 | #[derive(Debug)] | 16 | #[derive(Debug)] |
17 | pub struct ServerWorldState { | 17 | pub struct ServerWorldState { |
18 | pub analysis: WorldState, | 18 | pub analysis_host: AnalysisHost, |
19 | pub path_map: PathMap, | 19 | pub path_map: PathMap, |
20 | pub mem_map: HashMap<FileId, Option<String>>, | 20 | pub mem_map: HashMap<FileId, Option<String>>, |
21 | } | 21 | } |
@@ -29,7 +29,7 @@ pub struct ServerWorld { | |||
29 | impl ServerWorldState { | 29 | impl ServerWorldState { |
30 | pub fn new() -> ServerWorldState { | 30 | pub fn new() -> ServerWorldState { |
31 | ServerWorldState { | 31 | ServerWorldState { |
32 | analysis: WorldState::new(), | 32 | analysis_host: AnalysisHost::new(), |
33 | path_map: PathMap::new(), | 33 | path_map: PathMap::new(), |
34 | mem_map: HashMap::new(), | 34 | mem_map: HashMap::new(), |
35 | } | 35 | } |
@@ -58,20 +58,20 @@ impl ServerWorldState { | |||
58 | } | 58 | } |
59 | }); | 59 | }); |
60 | 60 | ||
61 | self.analysis.change_files(changes); | 61 | self.analysis_host.change_files(changes); |
62 | } | 62 | } |
63 | 63 | ||
64 | pub fn add_mem_file(&mut self, path: PathBuf, text: String) { | 64 | pub fn add_mem_file(&mut self, path: PathBuf, text: String) { |
65 | let file_id = self.path_map.get_or_insert(path); | 65 | let file_id = self.path_map.get_or_insert(path); |
66 | self.mem_map.insert(file_id, None); | 66 | self.mem_map.insert(file_id, None); |
67 | self.analysis.change_file(file_id, Some(text)); | 67 | self.analysis_host.change_file(file_id, Some(text)); |
68 | } | 68 | } |
69 | 69 | ||
70 | pub fn change_mem_file(&mut self, path: &Path, text: String) -> Result<()> { | 70 | pub fn change_mem_file(&mut self, path: &Path, text: String) -> Result<()> { |
71 | let file_id = self.path_map.get_id(path).ok_or_else(|| { | 71 | let file_id = self.path_map.get_id(path).ok_or_else(|| { |
72 | format_err!("change to unknown file: {}", path.display()) | 72 | format_err!("change to unknown file: {}", path.display()) |
73 | })?; | 73 | })?; |
74 | self.analysis.change_file(file_id, Some(text)); | 74 | self.analysis_host.change_file(file_id, Some(text)); |
75 | Ok(()) | 75 | Ok(()) |
76 | } | 76 | } |
77 | 77 | ||
@@ -85,13 +85,13 @@ impl ServerWorldState { | |||
85 | }; | 85 | }; |
86 | // Do this via file watcher ideally. | 86 | // Do this via file watcher ideally. |
87 | let text = fs::read_to_string(path).ok(); | 87 | let text = fs::read_to_string(path).ok(); |
88 | self.analysis.change_file(file_id, text); | 88 | self.analysis_host.change_file(file_id, text); |
89 | Ok(()) | 89 | Ok(()) |
90 | } | 90 | } |
91 | 91 | ||
92 | pub fn snapshot(&self) -> ServerWorld { | 92 | pub fn snapshot(&self) -> ServerWorld { |
93 | ServerWorld { | 93 | ServerWorld { |
94 | analysis: self.analysis.analysis(self.path_map.clone()), | 94 | analysis: self.analysis_host.analysis(self.path_map.clone()), |
95 | path_map: self.path_map.clone() | 95 | path_map: self.path_map.clone() |
96 | } | 96 | } |
97 | } | 97 | } |