7 use languageserver_types::Url;
8 use ra_analysis::{Analysis, AnalysisHost, AnalysisChange, CrateGraph, FileId, FileResolver, LibraryData};
9 use rustc_hash::FxHashMap;
12 path_map::{PathMap, Root},
13 project_model::CargoWorkspace,
14 vfs::{FileEvent, FileEventKind},
19 pub struct ServerWorldState {
20 pub workspaces: Arc<Vec<CargoWorkspace>>,
21 pub analysis_host: AnalysisHost,
22 pub path_map: PathMap,
23 pub mem_map: FxHashMap<FileId, Option<String>>,
26 pub struct ServerWorld {
27 pub workspaces: Arc<Vec<CargoWorkspace>>,
28 pub analysis: Analysis,
29 pub path_map: PathMap,
32 impl ServerWorldState {
33 pub fn new() -> ServerWorldState {
35 workspaces: Arc::new(Vec::new()),
36 analysis_host: AnalysisHost::new(),
37 path_map: PathMap::new(),
38 mem_map: FxHashMap::default(),
41 pub fn apply_fs_changes(&mut self, events: Vec<FileEvent>) {
42 let mut change = AnalysisChange::new();
43 let mut inserted = false;
45 let pm = &mut self.path_map;
46 let mm = &mut self.mem_map;
50 let text = match event.kind {
51 FileEventKind::Add(text) => text,
56 let (ins, file_id) = pm.get_or_insert(path, Root::Workspace);
60 .filter_map(|(file_id, text)| {
61 if mm.contains_key(&file_id) {
62 mm.insert(file_id, Some(text));
68 .for_each(|(file_id, text)| {
69 change.add_file(file_id, text)
73 change.set_file_resolver(Arc::new(self.path_map.clone()))
75 self.analysis_host.apply_change(change);
77 pub fn events_to_files(
79 events: Vec<FileEvent>,
80 ) -> (Vec<(FileId, String)>, Arc<FileResolver>) {
82 let pm = &mut self.path_map;
86 let FileEventKind::Add(text) = event.kind;
89 .map(|(path, text)| (pm.get_or_insert(path, Root::Lib).1, text))
92 let resolver = Arc::new(self.path_map.clone());
95 pub fn add_lib(&mut self, data: LibraryData) {
96 let mut change = AnalysisChange::new();
97 change.add_library(data);
98 self.analysis_host.apply_change(change);
101 pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId {
102 let (inserted, file_id) = self.path_map.get_or_insert(path, Root::Workspace);
103 if self.path_map.get_root(file_id) != Root::Lib {
104 let mut change = AnalysisChange::new();
106 change.add_file(file_id, text);
107 change.set_file_resolver(Arc::new(self.path_map.clone()));
109 change.change_file(file_id, text);
111 self.analysis_host.apply_change(change);
113 self.mem_map.insert(file_id, None);
117 pub fn change_mem_file(&mut self, path: &Path, text: String) -> Result<()> {
121 .ok_or_else(|| format_err!("change to unknown file: {}", path.display()))?;
122 if self.path_map.get_root(file_id) != Root::Lib {
123 let mut change = AnalysisChange::new();
124 change.change_file(file_id, text);
125 self.analysis_host.apply_change(change);
130 pub fn remove_mem_file(&mut self, path: &Path) -> Result<FileId> {
134 .ok_or_else(|| format_err!("change to unknown file: {}", path.display()))?;
135 match self.mem_map.remove(&file_id) {
137 None => bail!("unmatched close notification"),
139 // Do this via file watcher ideally.
140 let text = fs::read_to_string(path).ok();
141 if self.path_map.get_root(file_id) != Root::Lib {
142 let mut change = AnalysisChange::new();
143 if let Some(text) = text {
144 change.change_file(file_id, text);
146 self.analysis_host.apply_change(change);
150 pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) {
151 let mut crate_graph = CrateGraph::new();
155 .flat_map(move |pkg| pkg.targets(ws))
156 .map(move |tgt| tgt.root(ws))
159 if let Some(file_id) = self.path_map.get_id(root) {
160 crate_graph.add_crate_root(file_id);
163 self.workspaces = Arc::new(ws);
164 let mut change = AnalysisChange::new();
165 change.set_crate_graph(crate_graph);
166 self.analysis_host.apply_change(change);
168 pub fn snapshot(&self) -> ServerWorld {
170 workspaces: Arc::clone(&self.workspaces),
171 analysis: self.analysis_host.analysis(),
172 path_map: self.path_map.clone(),
178 pub fn analysis(&self) -> &Analysis {
182 pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> {
185 .map_err(|()| format_err!("invalid uri: {}", uri))?;
188 .ok_or_else(|| format_err!("unknown file: {}", path.display()))
191 pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
192 let path = self.path_map.get_path(id);
193 let url = Url::from_file_path(path)
194 .map_err(|()| format_err!("can't convert path to url: {}", path.display()))?;