use super::LanguageServerState;
use crate::{change::AnalysisChange, config::FilesWatcher};
use mun_paths::{AbsPathBuf, RelativePath};
use std::{
convert::{TryFrom, TryInto},
sync::Arc,
};
impl LanguageServerState {
pub(crate) fn fetch_workspaces(&mut self) {
let packages = self
.config
.discovered_projects
.clone()
.into_iter()
.flatten()
.filter_map(
|project| match mun_project::Package::from_file(&project.path) {
Ok(package) => Some(package),
Err(err) => {
self.show_message(
lsp_types::MessageType::ERROR,
format!("mun failed to load package: {:#}", err),
);
None
}
},
)
.collect::<Vec<_>>();
if *self.packages == packages {
return;
}
if self.config.watcher == FilesWatcher::Client {
let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions {
watchers: packages
.iter()
.map(|package| format!("{}/**/*.mun", package.source_directory().display()))
.map(|glob_pattern| lsp_types::FileSystemWatcher {
glob_pattern,
kind: None,
})
.collect(),
};
let registration = lsp_types::Registration {
id: "file-watcher".to_string(),
method: "workspace/didChangeWatchedFiles".to_string(),
register_options: Some(serde_json::to_value(registration_options).unwrap()),
};
self.send_request::<lsp_types::request::RegisterCapability>(
lsp_types::RegistrationParams {
registrations: vec![registration],
},
|_, _| {},
);
}
let mut change = AnalysisChange::new();
let entries_to_load = packages
.iter()
.map(|package| {
let source_dir: AbsPathBuf = package
.source_directory()
.try_into()
.expect("could not convert package root to absolute path");
mun_vfs::MonitorEntry::Directories(mun_vfs::MonitorDirectories {
extensions: vec!["mun".to_owned()],
include: vec![source_dir],
exclude: vec![],
})
})
.collect::<Vec<_>>();
let monitor_config = mun_vfs::MonitorConfig {
watch: match self.config.watcher {
FilesWatcher::Client => vec![],
FilesWatcher::Notify => (0..entries_to_load.len()).into_iter().collect(),
},
load: entries_to_load,
};
self.vfs_monitor.set_config(monitor_config);
let mut package_set = mun_hir::PackageSet::default();
for (idx, _package) in packages.iter().enumerate() {
package_set.add_package(mun_hir::SourceRootId(idx as u32));
}
change.set_packages(package_set);
self.packages = Arc::new(packages);
change.set_roots(self.recompute_source_roots());
self.analysis.apply_change(change);
}
pub(crate) fn recompute_source_roots(&self) -> Vec<mun_hir::SourceRoot> {
let mut source_roots = vec![mun_hir::SourceRoot::default(); self.packages.len()];
let source_dirs = self
.packages
.iter()
.map(|p| {
AbsPathBuf::try_from(p.source_directory())
.expect("must be able to convert source dir to absolute path")
})
.collect::<Vec<_>>();
let vfs = &*self.vfs.read();
for (file_id, path) in vfs.iter() {
if let Some((idx, relative_path)) =
source_dirs
.iter()
.enumerate()
.find_map(|(index, source_dir)| {
path.strip_prefix(source_dir)
.ok()
.and_then(|path| RelativePath::from_path(path).ok())
.map(|relative| (index, relative))
})
{
source_roots[idx].insert_file(mun_hir::FileId(file_id.0), relative_path);
}
}
source_roots
}
}