7 use languageserver_types::Url;
9 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FileResolver, LibraryData,
11 use rustc_hash::FxHashMap;
14 path_map::{PathMap, Root},
15 project_model::CargoWorkspace,
16 vfs::{FileEvent, FileEventKind},
20 #[derive(Debug, Default)]
21 pub struct ServerWorldState {
22 pub workspaces: Arc<Vec<CargoWorkspace>>,
23 pub analysis_host: AnalysisHost,
24 pub path_map: PathMap,
25 pub mem_map: FxHashMap<FileId, Option<String>>,
28 pub struct ServerWorld {
29 pub workspaces: Arc<Vec<CargoWorkspace>>,
30 pub analysis: Analysis,
31 pub path_map: PathMap,
34 impl ServerWorldState {
35 pub fn apply_fs_changes(&mut self, events: Vec<FileEvent>) {
36 let mut change = AnalysisChange::new();
37 let mut inserted = false;
39 let pm = &mut self.path_map;
40 let mm = &mut self.mem_map;
44 let text = match event.kind {
45 FileEventKind::Add(text) => text,
50 let (ins, file_id) = pm.get_or_insert(path, Root::Workspace);
54 .filter_map(|(file_id, text)| {
55 if mm.contains_key(&file_id) {
56 mm.insert(file_id, Some(text));
62 .for_each(|(file_id, text)| change.add_file(file_id, text));
65 change.set_file_resolver(Arc::new(self.path_map.clone()))
67 self.analysis_host.apply_change(change);
69 pub fn events_to_files(
71 events: Vec<FileEvent>,
72 ) -> (Vec<(FileId, String)>, Arc<FileResolver>) {
74 let pm = &mut self.path_map;
78 let FileEventKind::Add(text) = event.kind;
81 .map(|(path, text)| (pm.get_or_insert(path, Root::Lib).1, text))
84 let resolver = Arc::new(self.path_map.clone());
87 pub fn add_lib(&mut self, data: LibraryData) {
88 let mut change = AnalysisChange::new();
89 change.add_library(data);
90 self.analysis_host.apply_change(change);
93 pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId {
94 let (inserted, file_id) = self.path_map.get_or_insert(path, Root::Workspace);
95 if self.path_map.get_root(file_id) != Root::Lib {
96 let mut change = AnalysisChange::new();
98 change.add_file(file_id, text);
99 change.set_file_resolver(Arc::new(self.path_map.clone()));
101 change.change_file(file_id, text);
103 self.analysis_host.apply_change(change);
105 self.mem_map.insert(file_id, None);
109 pub fn change_mem_file(&mut self, path: &Path, text: String) -> Result<()> {
113 .ok_or_else(|| format_err!("change to unknown file: {}", path.display()))?;
114 if self.path_map.get_root(file_id) != Root::Lib {
115 let mut change = AnalysisChange::new();
116 change.change_file(file_id, text);
117 self.analysis_host.apply_change(change);
122 pub fn remove_mem_file(&mut self, path: &Path) -> Result<FileId> {
126 .ok_or_else(|| format_err!("change to unknown file: {}", path.display()))?;
127 match self.mem_map.remove(&file_id) {
129 None => bail!("unmatched close notification"),
131 // Do this via file watcher ideally.
132 let text = fs::read_to_string(path).ok();
133 if self.path_map.get_root(file_id) != Root::Lib {
134 let mut change = AnalysisChange::new();
135 if let Some(text) = text {
136 change.change_file(file_id, text);
138 self.analysis_host.apply_change(change);
142 pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) {
143 let mut crate_graph = CrateGraph::default();
147 .flat_map(move |pkg| pkg.targets(ws))
148 .map(move |tgt| tgt.root(ws))
151 if let Some(file_id) = self.path_map.get_id(root) {
152 crate_graph.add_crate_root(file_id);
155 self.workspaces = Arc::new(ws);
156 let mut change = AnalysisChange::new();
157 change.set_crate_graph(crate_graph);
158 self.analysis_host.apply_change(change);
160 pub fn snapshot(&self) -> ServerWorld {
162 workspaces: Arc::clone(&self.workspaces),
163 analysis: self.analysis_host.analysis(),
164 path_map: self.path_map.clone(),
170 pub fn analysis(&self) -> &Analysis {
174 pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> {
177 .map_err(|()| format_err!("invalid uri: {}", uri))?;
180 .ok_or_else(|| format_err!("unknown file: {}", path.display()))
183 pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
184 let path = self.path_map.get_path(id);
185 let url = Url::from_file_path(path)
186 .map_err(|()| format_err!("can't convert path to url: {}", path.display()))?;