aboutsummaryrefslogtreecommitdiff
path: root/crates/server/src/main_loop/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/server/src/main_loop/mod.rs')
-rw-r--r--crates/server/src/main_loop/mod.rs61
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 @@
1mod handlers; 1mod handlers;
2 2
3use std::collections::HashSet; 3use std::{
4 path::PathBuf,
5 collections::{HashSet, HashMap},
6};
4 7
5use threadpool::ThreadPool; 8use threadpool::ThreadPool;
6use crossbeam_channel::{Sender, Receiver}; 9use 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(),