use log::warn;
use tower_lsp::lsp_types::{Url, WorkspaceFolder};
use crate::{
error::{Error, Result as MyResult},
workspace::{InternalDocument, Workspace},
};
#[derive(Default, Debug)]
pub struct SyncBackend {
workspaces: Vec<Workspace>,
}
impl SyncBackend {
pub fn push_workspace(&mut self, workspace: Workspace) {
self.workspaces.push(workspace);
}
pub fn workspaces(&self) -> &Vec<Workspace> {
&self.workspaces
}
pub fn workspaces_mut(&mut self) -> &mut Vec<Workspace> {
&mut self.workspaces
}
pub fn get_or_insert_workspace_mut(&mut self, url: &Url) -> &mut Workspace {
let path = url.to_file_path().unwrap(); let maybe_index = self.workspaces.iter().position(|workspace| {
workspace.contains_internal_document(&path)
|| workspace.catalog_contains_url(url)
|| workspace.workspace_folder_is_base_of_url(url)
});
let index = if let Some(idx) = maybe_index {
idx
} else {
let mut file_path = url.to_file_path().expect("URL should be a filepath");
file_path.pop();
warn!("Workspace for {url} could not be found. Could the entry in catalog-v001.xml be missing? Creating a new one at {}", file_path.display());
let workspace_folder = WorkspaceFolder {
uri: Url::from_file_path(file_path).expect("Valid URL from filepath"),
name: "Single File".into(),
};
let workspace = Workspace::new(workspace_folder.clone());
self.workspaces.push(workspace);
self.workspaces.len() - 1
};
&mut self.workspaces[index]
}
pub fn get_workspace(&self, url: &Url) -> Option<&Workspace> {
let path = url
.to_file_path()
.unwrap_or_else(|()| panic!("Url should be path but was {url}"));
self.workspaces.iter().find(|workspace| {
workspace.contains_internal_document(&path)
|| workspace.catalog_contains_url(url)
|| workspace.workspace_folder_is_base_of_url(url)
})
}
pub fn get_internal_document(&self, url: &Url) -> MyResult<(&InternalDocument, &Workspace)> {
let workspace = self
.get_workspace(url)
.ok_or(Error::DocumentNotFound(url.clone()))?;
let path = url
.to_file_path()
.map_err(|()| Error::InvalidUrl(url.clone()))?;
Ok((workspace.get_internal_document(&path)?, workspace))
}
pub fn take_internal_document(
&mut self,
url: &Url,
) -> MyResult<(InternalDocument, &mut Workspace)> {
let workspace = self.get_or_insert_workspace_mut(url);
let path = url.to_file_path().unwrap(); Ok((workspace.take_internal_document(&path)?, workspace))
}
}