rust/crates/ra_lsp_server/src/server_world.rs

191 lines
6.2 KiB
Rust
Raw Normal View History

2018-08-17 18:54:08 +02:00
use std::{
2018-08-28 18:42:55 +02:00
fs,
path::{Path, PathBuf},
2018-09-02 13:46:15 +02:00
sync::Arc,
2018-08-17 18:54:08 +02:00
};
use languageserver_types::Url;
2018-10-31 21:41:43 +01:00
use ra_analysis::{
Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FileResolver, LibraryData,
};
use rustc_hash::FxHashMap;
2018-12-06 19:03:39 +01:00
use failure::{bail, format_err};
2018-08-17 18:54:08 +02:00
2018-10-15 19:15:53 +02:00
use crate::{
2018-09-04 10:40:45 +02:00
path_map::{PathMap, Root},
2018-09-02 13:46:15 +02:00
project_model::CargoWorkspace,
vfs::{FileEvent, FileEventKind},
Result,
2018-08-17 18:54:08 +02:00
};
2018-11-04 12:09:21 +01:00
#[derive(Debug, Default)]
2018-08-17 18:54:08 +02:00
pub struct ServerWorldState {
2018-09-02 13:46:15 +02:00
pub workspaces: Arc<Vec<CargoWorkspace>>,
2018-08-30 11:51:46 +02:00
pub analysis_host: AnalysisHost,
2018-08-17 18:54:08 +02:00
pub path_map: PathMap,
pub mem_map: FxHashMap<FileId, Option<String>>,
2018-08-17 18:54:08 +02:00
}
pub struct ServerWorld {
2018-09-02 13:46:15 +02:00
pub workspaces: Arc<Vec<CargoWorkspace>>,
2018-08-29 17:03:14 +02:00
pub analysis: Analysis,
2018-08-17 18:54:08 +02:00
pub path_map: PathMap,
}
impl ServerWorldState {
pub fn apply_fs_changes(&mut self, events: Vec<FileEvent>) {
let mut change = AnalysisChange::new();
let mut inserted = false;
{
let pm = &mut self.path_map;
let mm = &mut self.mem_map;
events
.into_iter()
.map(|event| {
let text = match event.kind {
FileEventKind::Add(text) => text,
};
(event.path, text)
})
.map(|(path, text)| {
let (ins, file_id) = pm.get_or_insert(path, Root::Workspace);
inserted |= ins;
(file_id, text)
})
.filter_map(|(file_id, text)| {
if mm.contains_key(&file_id) {
mm.insert(file_id, Some(text));
None
} else {
Some((file_id, text))
}
})
2018-10-31 21:41:43 +01:00
.for_each(|(file_id, text)| change.add_file(file_id, text));
}
if inserted {
change.set_file_resolver(Arc::new(self.path_map.clone()))
}
self.analysis_host.apply_change(change);
2018-08-17 18:54:08 +02:00
}
pub fn events_to_files(
&mut self,
events: Vec<FileEvent>,
) -> (Vec<(FileId, String)>, Arc<FileResolver>) {
2018-09-10 11:57:40 +02:00
let files = {
let pm = &mut self.path_map;
events
.into_iter()
2018-09-10 11:57:40 +02:00
.map(|event| {
let FileEventKind::Add(text) = event.kind;
2018-09-10 11:57:40 +02:00
(event.path, text)
})
.map(|(path, text)| (pm.get_or_insert(path, Root::Lib).1, text))
2018-09-10 11:57:40 +02:00
.collect()
};
let resolver = Arc::new(self.path_map.clone());
(files, resolver)
2018-09-03 20:26:59 +02:00
}
pub fn add_lib(&mut self, data: LibraryData) {
let mut change = AnalysisChange::new();
change.add_library(data);
self.analysis_host.apply_change(change);
2018-09-03 20:03:37 +02:00
}
2018-08-17 18:54:08 +02:00
2018-08-30 15:27:09 +02:00
pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId {
let (inserted, file_id) = self.path_map.get_or_insert(path, Root::Workspace);
2018-09-04 10:40:45 +02:00
if self.path_map.get_root(file_id) != Root::Lib {
let mut change = AnalysisChange::new();
if inserted {
change.add_file(file_id, text);
change.set_file_resolver(Arc::new(self.path_map.clone()));
} else {
change.change_file(file_id, text);
}
self.analysis_host.apply_change(change);
2018-09-04 10:40:45 +02:00
}
self.mem_map.insert(file_id, None);
2018-08-30 15:27:09 +02:00
file_id
2018-08-17 18:54:08 +02:00
}
pub fn change_mem_file(&mut self, path: &Path, text: String) -> Result<()> {
let file_id = self
.path_map
.get_id(path)
.ok_or_else(|| format_err!("change to unknown file: {}", path.display()))?;
2018-09-04 10:40:45 +02:00
if self.path_map.get_root(file_id) != Root::Lib {
let mut change = AnalysisChange::new();
change.change_file(file_id, text);
self.analysis_host.apply_change(change);
2018-09-04 10:40:45 +02:00
}
2018-08-17 18:54:08 +02:00
Ok(())
}
2018-08-30 15:27:09 +02:00
pub fn remove_mem_file(&mut self, path: &Path) -> Result<FileId> {
let file_id = self
.path_map
.get_id(path)
.ok_or_else(|| format_err!("change to unknown file: {}", path.display()))?;
2018-08-28 18:42:55 +02:00
match self.mem_map.remove(&file_id) {
Some(_) => (),
2018-08-17 18:54:08 +02:00
None => bail!("unmatched close notification"),
};
2018-08-28 18:42:55 +02:00
// Do this via file watcher ideally.
let text = fs::read_to_string(path).ok();
2018-09-04 10:40:45 +02:00
if self.path_map.get_root(file_id) != Root::Lib {
let mut change = AnalysisChange::new();
if let Some(text) = text {
change.change_file(file_id, text);
}
self.analysis_host.apply_change(change);
2018-09-04 10:40:45 +02:00
}
2018-08-30 15:27:09 +02:00
Ok(file_id)
2018-08-17 18:54:08 +02:00
}
2018-09-02 13:46:15 +02:00
pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) {
let mut crate_graph = CrateGraph::default();
2018-09-02 15:36:03 +02:00
ws.iter()
.flat_map(|ws| {
ws.packages()
.flat_map(move |pkg| pkg.targets(ws))
.map(move |tgt| tgt.root(ws))
})
.for_each(|root| {
if let Some(file_id) = self.path_map.get_id(root) {
2018-10-25 16:40:24 +02:00
crate_graph.add_crate_root(file_id);
}
});
2018-09-02 13:46:15 +02:00
self.workspaces = Arc::new(ws);
let mut change = AnalysisChange::new();
change.set_crate_graph(crate_graph);
self.analysis_host.apply_change(change);
2018-09-02 13:46:15 +02:00
}
2018-08-21 21:24:59 +02:00
pub fn snapshot(&self) -> ServerWorld {
2018-08-17 18:54:08 +02:00
ServerWorld {
2018-09-02 13:46:15 +02:00
workspaces: Arc::clone(&self.workspaces),
2018-09-10 11:57:40 +02:00
analysis: self.analysis_host.analysis(),
path_map: self.path_map.clone(),
2018-08-17 18:54:08 +02:00
}
}
}
impl ServerWorld {
2018-08-29 17:03:14 +02:00
pub fn analysis(&self) -> &Analysis {
2018-08-17 18:54:08 +02:00
&self.analysis
}
pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> {
let path = uri
.to_file_path()
2018-08-17 18:54:08 +02:00
.map_err(|()| format_err!("invalid uri: {}", uri))?;
self.path_map
.get_id(&path)
.ok_or_else(|| format_err!("unknown file: {}", path.display()))
2018-08-17 18:54:08 +02:00
}
pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
let path = self.path_map.get_path(id);
let url = Url::from_file_path(path)
.map_err(|()| format_err!("can't convert path to url: {}", path.display()))?;
Ok(url)
}
}