aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--code/src/extension.ts2
-rw-r--r--crates/libanalysis/src/api.rs35
-rw-r--r--crates/libanalysis/src/imp.rs58
-rw-r--r--crates/libanalysis/src/lib.rs86
-rw-r--r--crates/server/src/server_world.rs16
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 @@
1use relative_path::RelativePathBuf; 1use relative_path::{RelativePath, RelativePathBuf};
2use libsyntax2::{File, TextRange, TextUnit, AtomEdit}; 2use libsyntax2::{File, TextRange, TextUnit, AtomEdit};
3use libeditor; 3use libeditor;
4use {imp::AnalysisImpl, FileId, Query}; 4use {imp::{AnalysisImpl, AnalysisHostImpl}, Query};
5 5
6pub use libeditor::{ 6pub 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
113pub 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)]
119pub struct FileId(pub u32);
120
121#[derive(Debug)]
122pub struct AnalysisHost {
123 pub(crate) imp: AnalysisHostImpl
124}
125
126impl 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)]
29pub(crate) struct AnalysisHostImpl {
30 data: Arc<WorldData>
31}
32
33impl 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
29pub(crate) struct AnalysisImpl { 85pub(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;
14mod api; 14mod api;
15mod imp; 15mod imp;
16 16
17use std::{
18 sync::{
19 Arc,
20 atomic::{AtomicBool},
21 },
22};
23
24use relative_path::RelativePath;
25
26use self::{
27 module_map::{ChangeKind},
28 imp::{WorldData, FileData},
29};
30pub use self::symbol_index::Query; 17pub use self::symbol_index::Query;
31pub use self::api::{ 18pub 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
35pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 23pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
36
37pub 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)]
43pub struct WorldState {
44 data: Arc<WorldData>
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
48pub struct FileId(pub u32);
49
50impl 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
7use languageserver_types::Url; 7use languageserver_types::Url;
8use libanalysis::{FileId, WorldState, Analysis}; 8use libanalysis::{FileId, AnalysisHost, Analysis};
9 9
10use { 10use {
11 Result, 11 Result,
@@ -15,7 +15,7 @@ use {
15 15
16#[derive(Debug)] 16#[derive(Debug)]
17pub struct ServerWorldState { 17pub 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 {
29impl ServerWorldState { 29impl 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 }