diff options
Diffstat (limited to 'crates/server/src')
-rw-r--r-- | crates/server/src/main_loop/handlers.rs | 6 | ||||
-rw-r--r-- | crates/server/src/main_loop/mod.rs | 62 | ||||
-rw-r--r-- | crates/server/src/project_model.rs | 29 | ||||
-rw-r--r-- | crates/server/src/server_world.rs | 13 | ||||
-rw-r--r-- | crates/server/src/vfs.rs | 76 |
5 files changed, 115 insertions, 71 deletions
diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index 898195f6d..323d4e95e 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs | |||
@@ -141,14 +141,18 @@ pub fn handle_workspace_symbol( | |||
141 | token: JobToken, | 141 | token: JobToken, |
142 | ) -> Result<Option<Vec<SymbolInformation>>> { | 142 | ) -> Result<Option<Vec<SymbolInformation>>> { |
143 | let all_symbols = params.query.contains("#"); | 143 | let all_symbols = params.query.contains("#"); |
144 | let libs = params.query.contains("*"); | ||
144 | let query = { | 145 | let query = { |
145 | let query: String = params.query.chars() | 146 | let query: String = params.query.chars() |
146 | .filter(|&c| c != '#') | 147 | .filter(|&c| c != '#' && c != '*') |
147 | .collect(); | 148 | .collect(); |
148 | let mut q = Query::new(query); | 149 | let mut q = Query::new(query); |
149 | if !all_symbols { | 150 | if !all_symbols { |
150 | q.only_types(); | 151 | q.only_types(); |
151 | } | 152 | } |
153 | if libs { | ||
154 | q.libs(); | ||
155 | } | ||
152 | q.limit(128); | 156 | q.limit(128); |
153 | q | 157 | q |
154 | }; | 158 | }; |
diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index bb1d638e0..ce61265a2 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs | |||
@@ -38,9 +38,8 @@ pub fn main_loop( | |||
38 | ) -> Result<()> { | 38 | ) -> Result<()> { |
39 | let pool = ThreadPool::new(4); | 39 | let pool = ThreadPool::new(4); |
40 | let (task_sender, task_receiver) = bounded::<Task>(16); | 40 | let (task_sender, task_receiver) = bounded::<Task>(16); |
41 | let (fs_events_receiver, watcher) = vfs::watch(vec![root.clone()]); | 41 | let (fs_sender, fs_receiver, fs_watcher) = vfs::roots_loader(); |
42 | let (ws_root_sender, ws_receiver, ws_watcher) = workspace_loader(); | 42 | let (ws_sender, ws_receiver, ws_watcher) = workspace_loader(); |
43 | ws_root_sender.send(root); | ||
44 | 43 | ||
45 | info!("server initialized, serving requests"); | 44 | info!("server initialized, serving requests"); |
46 | let mut state = ServerWorldState::new(); | 45 | let mut state = ServerWorldState::new(); |
@@ -48,13 +47,15 @@ pub fn main_loop( | |||
48 | let mut pending_requests = HashMap::new(); | 47 | let mut pending_requests = HashMap::new(); |
49 | let mut subs = Subscriptions::new(); | 48 | let mut subs = Subscriptions::new(); |
50 | let main_res = main_loop_inner( | 49 | let main_res = main_loop_inner( |
50 | root, | ||
51 | &pool, | 51 | &pool, |
52 | msg_receriver, | ||
53 | msg_sender, | 52 | msg_sender, |
54 | task_receiver.clone(), | 53 | msg_receriver, |
55 | task_sender, | 54 | task_sender, |
56 | fs_events_receiver, | 55 | task_receiver.clone(), |
57 | ws_root_sender, | 56 | fs_sender, |
57 | fs_receiver, | ||
58 | ws_sender, | ||
58 | ws_receiver, | 59 | ws_receiver, |
59 | &mut state, | 60 | &mut state, |
60 | &mut pending_requests, | 61 | &mut pending_requests, |
@@ -68,38 +69,40 @@ pub fn main_loop( | |||
68 | pool.join(); | 69 | pool.join(); |
69 | info!("...threadpool has finished"); | 70 | info!("...threadpool has finished"); |
70 | 71 | ||
71 | let vfs_res = watcher.stop(); | 72 | let fs_res = fs_watcher.stop(); |
72 | let ws_res = ws_watcher.stop(); | 73 | let ws_res = ws_watcher.stop(); |
73 | 74 | ||
74 | main_res?; | 75 | main_res?; |
75 | vfs_res?; | 76 | fs_res?; |
76 | ws_res?; | 77 | ws_res?; |
77 | 78 | ||
78 | Ok(()) | 79 | Ok(()) |
79 | } | 80 | } |
80 | 81 | ||
81 | fn main_loop_inner( | 82 | fn main_loop_inner( |
83 | ws_root: PathBuf, | ||
82 | pool: &ThreadPool, | 84 | pool: &ThreadPool, |
83 | msg_receiver: &mut Receiver<RawMessage>, | ||
84 | msg_sender: &mut Sender<RawMessage>, | 85 | msg_sender: &mut Sender<RawMessage>, |
85 | task_receiver: Receiver<Task>, | 86 | msg_receiver: &mut Receiver<RawMessage>, |
86 | task_sender: Sender<Task>, | 87 | task_sender: Sender<Task>, |
87 | fs_receiver: Receiver<Vec<FileEvent>>, | 88 | task_receiver: Receiver<Task>, |
88 | _ws_roots_sender: Sender<PathBuf>, | 89 | fs_sender: Sender<PathBuf>, |
90 | fs_receiver: Receiver<(PathBuf, Vec<FileEvent>)>, | ||
91 | ws_sender: Sender<PathBuf>, | ||
89 | ws_receiver: Receiver<Result<CargoWorkspace>>, | 92 | ws_receiver: Receiver<Result<CargoWorkspace>>, |
90 | state: &mut ServerWorldState, | 93 | state: &mut ServerWorldState, |
91 | pending_requests: &mut HashMap<u64, JobHandle>, | 94 | pending_requests: &mut HashMap<u64, JobHandle>, |
92 | subs: &mut Subscriptions, | 95 | subs: &mut Subscriptions, |
93 | ) -> Result<()> { | 96 | ) -> Result<()> { |
94 | let mut fs_receiver = Some(fs_receiver); | 97 | ws_sender.send(ws_root.clone()); |
98 | fs_sender.send(ws_root.clone()); | ||
95 | loop { | 99 | loop { |
96 | #[derive(Debug)] | 100 | #[derive(Debug)] |
97 | enum Event { | 101 | enum Event { |
98 | Msg(RawMessage), | 102 | Msg(RawMessage), |
99 | Task(Task), | 103 | Task(Task), |
100 | Fs(Vec<FileEvent>), | 104 | Fs(PathBuf, Vec<FileEvent>), |
101 | Ws(Result<CargoWorkspace>), | 105 | Ws(Result<CargoWorkspace>), |
102 | FsWatcherDead, | ||
103 | } | 106 | } |
104 | trace!("selecting"); | 107 | trace!("selecting"); |
105 | let event = select! { | 108 | let event = select! { |
@@ -109,8 +112,8 @@ fn main_loop_inner( | |||
109 | }, | 112 | }, |
110 | recv(task_receiver, task) => Event::Task(task.unwrap()), | 113 | recv(task_receiver, task) => Event::Task(task.unwrap()), |
111 | recv(fs_receiver, events) => match events { | 114 | recv(fs_receiver, events) => match events { |
112 | Some(events) => Event::Fs(events), | 115 | None => bail!("roots watcher died"), |
113 | None => Event::FsWatcherDead, | 116 | Some((pb, events)) => Event::Fs(pb, events), |
114 | } | 117 | } |
115 | recv(ws_receiver, ws) => match ws { | 118 | recv(ws_receiver, ws) => match ws { |
116 | None => bail!("workspace watcher died"), | 119 | None => bail!("workspace watcher died"), |
@@ -120,19 +123,30 @@ fn main_loop_inner( | |||
120 | trace!("selected {:?}", event); | 123 | trace!("selected {:?}", event); |
121 | let mut state_changed = false; | 124 | let mut state_changed = false; |
122 | match event { | 125 | match event { |
123 | Event::FsWatcherDead => fs_receiver = None, | ||
124 | Event::Task(task) => on_task(task, msg_sender, pending_requests), | 126 | Event::Task(task) => on_task(task, msg_sender, pending_requests), |
125 | Event::Fs(events) => { | 127 | Event::Fs(root, events) => { |
126 | trace!("fs change, {} events", events.len()); | 128 | info!("fs change, {}, {} events", root.display(), events.len()); |
127 | state.apply_fs_changes(events); | 129 | if root == ws_root { |
130 | state.apply_fs_changes(events); | ||
131 | } else { | ||
132 | state.add_library(events); | ||
133 | } | ||
128 | state_changed = true; | 134 | state_changed = true; |
129 | } | 135 | } |
130 | Event::Ws(ws) => { | 136 | Event::Ws(ws) => { |
131 | match ws { | 137 | match ws { |
132 | Ok(ws) => { | 138 | Ok(ws) => { |
133 | let not = RawNotification::new::<req::DidReloadWorkspace>(&vec![ws.clone()]); | 139 | let workspaces = vec![ws]; |
140 | let not = RawNotification::new::<req::DidReloadWorkspace>(&workspaces); | ||
134 | msg_sender.send(RawMessage::Notification(not)); | 141 | msg_sender.send(RawMessage::Notification(not)); |
135 | state.set_workspaces(vec![ws]); | 142 | for ws in workspaces.iter() { |
143 | for pkg in ws.packages().filter(|pkg| !pkg.is_member(ws)) { | ||
144 | debug!("sending root, {}", pkg.root(ws).to_path_buf().display()); | ||
145 | // deadlocky :-( | ||
146 | fs_sender.send(pkg.root(ws).to_path_buf()); | ||
147 | } | ||
148 | } | ||
149 | state.set_workspaces(workspaces); | ||
136 | state_changed = true; | 150 | state_changed = true; |
137 | } | 151 | } |
138 | Err(e) => warn!("loading workspace failed: {}", e), | 152 | Err(e) => warn!("loading workspace failed: {}", e), |
diff --git a/crates/server/src/project_model.rs b/crates/server/src/project_model.rs index 12233f258..517836e62 100644 --- a/crates/server/src/project_model.rs +++ b/crates/server/src/project_model.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | collections::HashMap, | 2 | collections::{HashMap, HashSet}, |
3 | path::{Path, PathBuf}, | 3 | path::{Path, PathBuf}, |
4 | }; | 4 | }; |
5 | use cargo_metadata::{metadata_run, CargoOpt}; | 5 | use cargo_metadata::{metadata_run, CargoOpt}; |
@@ -13,7 +13,6 @@ use { | |||
13 | 13 | ||
14 | #[derive(Debug, Serialize, Clone)] | 14 | #[derive(Debug, Serialize, Clone)] |
15 | pub struct CargoWorkspace { | 15 | pub struct CargoWorkspace { |
16 | ws_members: Vec<Package>, | ||
17 | packages: Vec<PackageData>, | 16 | packages: Vec<PackageData>, |
18 | targets: Vec<TargetData>, | 17 | targets: Vec<TargetData>, |
19 | } | 18 | } |
@@ -27,7 +26,8 @@ pub struct Target(usize); | |||
27 | struct PackageData { | 26 | struct PackageData { |
28 | name: SmolStr, | 27 | name: SmolStr, |
29 | manifest: PathBuf, | 28 | manifest: PathBuf, |
30 | targets: Vec<Target> | 29 | targets: Vec<Target>, |
30 | is_member: bool, | ||
31 | } | 31 | } |
32 | 32 | ||
33 | #[derive(Debug, Serialize, Clone)] | 33 | #[derive(Debug, Serialize, Clone)] |
@@ -50,9 +50,15 @@ impl Package { | |||
50 | pub fn manifest(self, ws: &CargoWorkspace) -> &Path { | 50 | pub fn manifest(self, ws: &CargoWorkspace) -> &Path { |
51 | ws.pkg(self).manifest.as_path() | 51 | ws.pkg(self).manifest.as_path() |
52 | } | 52 | } |
53 | pub fn root(self, ws: &CargoWorkspace) -> &Path { | ||
54 | ws.pkg(self).manifest.parent().unwrap() | ||
55 | } | ||
53 | pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item=Target> + 'a { | 56 | pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item=Target> + 'a { |
54 | ws.pkg(self).targets.iter().cloned() | 57 | ws.pkg(self).targets.iter().cloned() |
55 | } | 58 | } |
59 | pub fn is_member(self, ws: &CargoWorkspace) -> bool { | ||
60 | ws.pkg(self).is_member | ||
61 | } | ||
56 | } | 62 | } |
57 | 63 | ||
58 | impl Target { | 64 | impl Target { |
@@ -81,13 +87,21 @@ impl CargoWorkspace { | |||
81 | let mut pkg_by_id = HashMap::new(); | 87 | let mut pkg_by_id = HashMap::new(); |
82 | let mut packages = Vec::new(); | 88 | let mut packages = Vec::new(); |
83 | let mut targets = Vec::new(); | 89 | let mut targets = Vec::new(); |
90 | |||
91 | let ws_members: HashSet<String> = meta.workspace_members | ||
92 | .into_iter() | ||
93 | .map(|it| it.raw) | ||
94 | .collect(); | ||
95 | |||
84 | for meta_pkg in meta.packages { | 96 | for meta_pkg in meta.packages { |
85 | let pkg = Package(packages.len()); | 97 | let pkg = Package(packages.len()); |
98 | let is_member = ws_members.contains(&meta_pkg.id); | ||
86 | pkg_by_id.insert(meta_pkg.id.clone(), pkg); | 99 | pkg_by_id.insert(meta_pkg.id.clone(), pkg); |
87 | let mut pkg_data = PackageData { | 100 | let mut pkg_data = PackageData { |
88 | name: meta_pkg.name.into(), | 101 | name: meta_pkg.name.into(), |
89 | manifest: PathBuf::from(meta_pkg.manifest_path), | 102 | manifest: PathBuf::from(meta_pkg.manifest_path), |
90 | targets: Vec::new(), | 103 | targets: Vec::new(), |
104 | is_member, | ||
91 | }; | 105 | }; |
92 | for meta_tgt in meta_pkg.targets { | 106 | for meta_tgt in meta_pkg.targets { |
93 | let tgt = Target(targets.len()); | 107 | let tgt = Target(targets.len()); |
@@ -101,19 +115,12 @@ impl CargoWorkspace { | |||
101 | } | 115 | } |
102 | packages.push(pkg_data) | 116 | packages.push(pkg_data) |
103 | } | 117 | } |
104 | let ws_members = meta.workspace_members | ||
105 | .iter() | ||
106 | .map(|it| pkg_by_id[&it.raw]) | ||
107 | .collect(); | ||
108 | 118 | ||
109 | Ok(CargoWorkspace { packages, targets, ws_members }) | 119 | Ok(CargoWorkspace { packages, targets }) |
110 | } | 120 | } |
111 | pub fn packages<'a>(&'a self) -> impl Iterator<Item=Package> + 'a { | 121 | pub fn packages<'a>(&'a self) -> impl Iterator<Item=Package> + 'a { |
112 | (0..self.packages.len()).map(Package) | 122 | (0..self.packages.len()).map(Package) |
113 | } | 123 | } |
114 | pub fn ws_members<'a>(&'a self) -> impl Iterator<Item=Package> + 'a { | ||
115 | self.ws_members.iter().cloned() | ||
116 | } | ||
117 | pub fn target_by_root(&self, root: &Path) -> Option<Target> { | 124 | pub fn target_by_root(&self, root: &Path) -> Option<Target> { |
118 | self.packages() | 125 | self.packages() |
119 | .filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)) | 126 | .filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)) |
diff --git a/crates/server/src/server_world.rs b/crates/server/src/server_world.rs index f78b56cf8..95c109e10 100644 --- a/crates/server/src/server_world.rs +++ b/crates/server/src/server_world.rs | |||
@@ -47,7 +47,6 @@ impl ServerWorldState { | |||
47 | .map(|event| { | 47 | .map(|event| { |
48 | let text = match event.kind { | 48 | let text = match event.kind { |
49 | FileEventKind::Add(text) => Some(text), | 49 | FileEventKind::Add(text) => Some(text), |
50 | FileEventKind::Remove => None, | ||
51 | }; | 50 | }; |
52 | (event.path, text) | 51 | (event.path, text) |
53 | }) | 52 | }) |
@@ -65,6 +64,18 @@ impl ServerWorldState { | |||
65 | 64 | ||
66 | self.analysis_host.change_files(changes); | 65 | self.analysis_host.change_files(changes); |
67 | } | 66 | } |
67 | pub fn add_library(&mut self, events: Vec<FileEvent>) { | ||
68 | let pm = &mut self.path_map; | ||
69 | let files = events.into_iter() | ||
70 | .map(|event| { | ||
71 | let text = match event.kind { | ||
72 | FileEventKind::Add(text) => text, | ||
73 | }; | ||
74 | (event.path, text) | ||
75 | }) | ||
76 | .map(|(path, text)| (pm.get_or_insert(path), text)); | ||
77 | self.analysis_host.add_library(files); | ||
78 | } | ||
68 | 79 | ||
69 | pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId { | 80 | pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId { |
70 | let file_id = self.path_map.get_or_insert(path); | 81 | let file_id = self.path_map.get_or_insert(path); |
diff --git a/crates/server/src/vfs.rs b/crates/server/src/vfs.rs index 2acc3f55f..69a7654af 100644 --- a/crates/server/src/vfs.rs +++ b/crates/server/src/vfs.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | path::PathBuf, | 2 | path::{PathBuf, Path}, |
3 | fs, | 3 | fs, |
4 | }; | 4 | }; |
5 | 5 | ||
@@ -20,46 +20,54 @@ pub struct FileEvent { | |||
20 | #[derive(Debug)] | 20 | #[derive(Debug)] |
21 | pub enum FileEventKind { | 21 | pub enum FileEventKind { |
22 | Add(String), | 22 | Add(String), |
23 | #[allow(unused)] | ||
24 | Remove, | ||
25 | } | 23 | } |
26 | 24 | ||
27 | pub fn watch(roots: Vec<PathBuf>) -> (Receiver<Vec<FileEvent>>, ThreadWatcher) { | 25 | pub fn roots_loader() -> (Sender<PathBuf>, Receiver<(PathBuf, Vec<FileEvent>)>, ThreadWatcher) { |
28 | let (sender, receiver) = bounded(16); | 26 | let (path_sender, path_receiver) = bounded::<PathBuf>(2048); |
29 | let watcher = ThreadWatcher::spawn("vfs", move || run(roots, sender)); | 27 | let (event_sender, event_receiver) = bounded::<(PathBuf, Vec<FileEvent>)>(1); |
30 | (receiver, watcher) | 28 | let thread = ThreadWatcher::spawn("roots loader", move || { |
29 | path_receiver | ||
30 | .into_iter() | ||
31 | .map(|path| { | ||
32 | debug!("loading {} ...", path.as_path().display()); | ||
33 | let events = load_root(path.as_path()); | ||
34 | debug!("... loaded {}", path.as_path().display()); | ||
35 | (path, events) | ||
36 | }) | ||
37 | .for_each(|it| event_sender.send(it)) | ||
38 | }); | ||
39 | |||
40 | (path_sender, event_receiver, thread) | ||
31 | } | 41 | } |
32 | 42 | ||
33 | fn run(roots: Vec<PathBuf>, sender: Sender<Vec<FileEvent>>) { | 43 | fn load_root(path: &Path) -> Vec<FileEvent> { |
34 | for root in roots { | 44 | let mut res = Vec::new(); |
35 | let mut events = Vec::new(); | 45 | for entry in WalkDir::new(path) { |
36 | for entry in WalkDir::new(root.as_path()) { | 46 | let entry = match entry { |
37 | let entry = match entry { | 47 | Ok(entry) => entry, |
38 | Ok(entry) => entry, | 48 | Err(e) => { |
39 | Err(e) => { | 49 | warn!("watcher error: {}", e); |
40 | warn!("watcher error: {}", e); | ||
41 | continue; | ||
42 | } | ||
43 | }; | ||
44 | if !entry.file_type().is_file() { | ||
45 | continue; | 50 | continue; |
46 | } | 51 | } |
47 | let path = entry.path(); | 52 | }; |
48 | if path.extension().and_then(|os| os.to_str()) != Some("rs") { | 53 | if !entry.file_type().is_file() { |
54 | continue; | ||
55 | } | ||
56 | let path = entry.path(); | ||
57 | if path.extension().and_then(|os| os.to_str()) != Some("rs") { | ||
58 | continue; | ||
59 | } | ||
60 | let text = match fs::read_to_string(path) { | ||
61 | Ok(text) => text, | ||
62 | Err(e) => { | ||
63 | warn!("watcher error: {}", e); | ||
49 | continue; | 64 | continue; |
50 | } | 65 | } |
51 | let text = match fs::read_to_string(path) { | 66 | }; |
52 | Ok(text) => text, | 67 | res.push(FileEvent { |
53 | Err(e) => { | 68 | path: path.to_owned(), |
54 | warn!("watcher error: {}", e); | 69 | kind: FileEventKind::Add(text), |
55 | continue; | 70 | }) |
56 | } | ||
57 | }; | ||
58 | events.push(FileEvent { | ||
59 | path: path.to_owned(), | ||
60 | kind: FileEventKind::Add(text), | ||
61 | }) | ||
62 | } | ||
63 | sender.send(events) | ||
64 | } | 71 | } |
72 | res | ||
65 | } | 73 | } |