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