diff options
Diffstat (limited to 'crates/server/src/main_loop/mod.rs')
-rw-r--r-- | crates/server/src/main_loop/mod.rs | 61 |
1 files changed, 52 insertions, 9 deletions
diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index 5b7093ad7..f954e632c 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | mod handlers; | 1 | mod handlers; |
2 | 2 | ||
3 | use std::collections::HashSet; | 3 | use std::{ |
4 | path::PathBuf, | ||
5 | collections::{HashSet, HashMap}, | ||
6 | }; | ||
4 | 7 | ||
5 | use threadpool::ThreadPool; | 8 | use threadpool::ThreadPool; |
6 | use crossbeam_channel::{Sender, Receiver}; | 9 | use crossbeam_channel::{Sender, Receiver}; |
@@ -13,6 +16,7 @@ use { | |||
13 | Task, Result, | 16 | Task, Result, |
14 | io::{Io, RawMsg, RawRequest, RawNotification}, | 17 | io::{Io, RawMsg, RawRequest, RawNotification}, |
15 | util::FilePath, | 18 | util::FilePath, |
19 | vfs::{FileEvent, FileEventKind}, | ||
16 | main_loop::handlers::{ | 20 | main_loop::handlers::{ |
17 | handle_syntax_tree, | 21 | handle_syntax_tree, |
18 | handle_extend_selection, | 22 | handle_extend_selection, |
@@ -28,24 +32,33 @@ pub(super) fn main_loop( | |||
28 | io: &mut Io, | 32 | io: &mut Io, |
29 | world: &mut WorldState, | 33 | world: &mut WorldState, |
30 | pool: &mut ThreadPool, | 34 | pool: &mut ThreadPool, |
31 | sender: Sender<Task>, | 35 | task_sender: Sender<Task>, |
32 | receiver: Receiver<Task>, | 36 | task_receiver: Receiver<Task>, |
37 | fs_events_receiver: Receiver<Vec<FileEvent>>, | ||
33 | ) -> Result<()> { | 38 | ) -> Result<()> { |
34 | info!("server initialized, serving requests"); | 39 | info!("server initialized, serving requests"); |
35 | let mut next_request_id = 0; | 40 | let mut next_request_id = 0; |
36 | let mut pending_requests: HashSet<u64> = HashSet::new(); | 41 | let mut pending_requests: HashSet<u64> = HashSet::new(); |
42 | let mut mem_map: HashMap<PathBuf, Option<String>> = HashMap::new(); | ||
43 | let mut fs_events_receiver = Some(&fs_events_receiver); | ||
37 | loop { | 44 | loop { |
38 | enum Event { | 45 | enum Event { |
39 | Msg(RawMsg), | 46 | Msg(RawMsg), |
40 | Task(Task), | 47 | Task(Task), |
48 | Fs(Vec<FileEvent>), | ||
41 | ReceiverDead, | 49 | ReceiverDead, |
50 | FsWatcherDead, | ||
42 | } | 51 | } |
43 | let event = select! { | 52 | let event = select! { |
44 | recv(io.receiver(), msg) => match msg { | 53 | recv(io.receiver(), msg) => match msg { |
45 | Some(msg) => Event::Msg(msg), | 54 | Some(msg) => Event::Msg(msg), |
46 | None => Event::ReceiverDead, | 55 | None => Event::ReceiverDead, |
47 | }, | 56 | }, |
48 | recv(receiver, task) => Event::Task(task.unwrap()), | 57 | recv(task_receiver, task) => Event::Task(task.unwrap()), |
58 | recv(fs_events_receiver, events) => match events { | ||
59 | Some(events) => Event::Fs(events), | ||
60 | None => Event::FsWatcherDead, | ||
61 | } | ||
49 | }; | 62 | }; |
50 | 63 | ||
51 | match event { | 64 | match event { |
@@ -53,6 +66,9 @@ pub(super) fn main_loop( | |||
53 | io.cleanup_receiver()?; | 66 | io.cleanup_receiver()?; |
54 | unreachable!(); | 67 | unreachable!(); |
55 | } | 68 | } |
69 | Event::FsWatcherDead => { | ||
70 | fs_events_receiver = None; | ||
71 | } | ||
56 | Event::Task(task) => { | 72 | Event::Task(task) => { |
57 | match task { | 73 | match task { |
58 | Task::Request(mut request) => { | 74 | Task::Request(mut request) => { |
@@ -70,15 +86,36 @@ pub(super) fn main_loop( | |||
70 | } | 86 | } |
71 | continue; | 87 | continue; |
72 | } | 88 | } |
89 | Event::Fs(events) => { | ||
90 | trace!("fs change, {} events", events.len()); | ||
91 | let changes = events.into_iter() | ||
92 | .map(|event| { | ||
93 | let text = match event.kind { | ||
94 | FileEventKind::Add(text) => Some(text), | ||
95 | FileEventKind::Remove => None, | ||
96 | }; | ||
97 | (event.path, text) | ||
98 | }) | ||
99 | .filter_map(|(path, text)| { | ||
100 | if mem_map.contains_key(path.as_path()) { | ||
101 | mem_map.insert(path, text); | ||
102 | None | ||
103 | } else { | ||
104 | Some((path, text)) | ||
105 | } | ||
106 | }); | ||
107 | |||
108 | world.change_files(changes); | ||
109 | } | ||
73 | Event::Msg(msg) => { | 110 | Event::Msg(msg) => { |
74 | match msg { | 111 | match msg { |
75 | RawMsg::Request(req) => { | 112 | RawMsg::Request(req) => { |
76 | if !on_request(io, world, pool, &sender, req)? { | 113 | if !on_request(io, world, pool, &task_sender, req)? { |
77 | return Ok(()); | 114 | return Ok(()); |
78 | } | 115 | } |
79 | } | 116 | } |
80 | RawMsg::Notification(not) => { | 117 | RawMsg::Notification(not) => { |
81 | on_notification(io, world, pool, &sender, not)? | 118 | on_notification(io, world, pool, &task_sender, not, &mut mem_map)? |
82 | } | 119 | } |
83 | RawMsg::Response(resp) => { | 120 | RawMsg::Response(resp) => { |
84 | if !pending_requests.remove(&resp.id) { | 121 | if !pending_requests.remove(&resp.id) { |
@@ -160,11 +197,13 @@ fn on_notification( | |||
160 | pool: &ThreadPool, | 197 | pool: &ThreadPool, |
161 | sender: &Sender<Task>, | 198 | sender: &Sender<Task>, |
162 | not: RawNotification, | 199 | not: RawNotification, |
200 | mem_map: &mut HashMap<PathBuf, Option<String>>, | ||
163 | ) -> Result<()> { | 201 | ) -> Result<()> { |
164 | let mut not = Some(not); | 202 | let mut not = Some(not); |
165 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { | 203 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { |
166 | let path = params.text_document.file_path()?; | 204 | let path = params.text_document.file_path()?; |
167 | world.change_overlay(path, Some(params.text_document.text)); | 205 | mem_map.insert(path.clone(), None); |
206 | world.change_file(path, Some(params.text_document.text)); | ||
168 | update_file_notifications_on_threadpool( | 207 | update_file_notifications_on_threadpool( |
169 | pool, world.snapshot(), sender.clone(), params.text_document.uri, | 208 | pool, world.snapshot(), sender.clone(), params.text_document.uri, |
170 | ); | 209 | ); |
@@ -175,7 +214,7 @@ fn on_notification( | |||
175 | let text = params.content_changes.pop() | 214 | let text = params.content_changes.pop() |
176 | .ok_or_else(|| format_err!("empty changes"))? | 215 | .ok_or_else(|| format_err!("empty changes"))? |
177 | .text; | 216 | .text; |
178 | world.change_overlay(path, Some(text)); | 217 | world.change_file(path, Some(text)); |
179 | update_file_notifications_on_threadpool( | 218 | update_file_notifications_on_threadpool( |
180 | pool, world.snapshot(), sender.clone(), params.text_document.uri, | 219 | pool, world.snapshot(), sender.clone(), params.text_document.uri, |
181 | ); | 220 | ); |
@@ -183,7 +222,11 @@ fn on_notification( | |||
183 | })?; | 222 | })?; |
184 | dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { | 223 | dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { |
185 | let path = params.text_document.file_path()?; | 224 | let path = params.text_document.file_path()?; |
186 | world.change_overlay(path, None); | 225 | let text = match mem_map.remove(&path) { |
226 | Some(text) => text, | ||
227 | None => bail!("unmatched close notification"), | ||
228 | }; | ||
229 | world.change_file(path, text); | ||
187 | let not = req::PublishDiagnosticsParams { | 230 | let not = req::PublishDiagnosticsParams { |
188 | uri: params.text_document.uri, | 231 | uri: params.text_document.uri, |
189 | diagnostics: Vec::new(), | 232 | diagnostics: Vec::new(), |