use std::collections::HashMap;
use camino::Utf8PathBuf;
use crate::repository::open_repository::OpenRepository;
use crate::vscode_sys;
mod open_repository;
#[derive(Default)]
pub struct OpenRepositories {
repositories: HashMap<Utf8PathBuf, OpenRepository>,
}
impl OpenRepositories {
#[tracing::instrument(skip_all)]
pub fn new() -> Self {
Self::default()
}
#[tracing::instrument(skip_all)]
pub fn get_open_repository(
&self,
env: &napi::Env,
uri: &vscode_sys::Uri,
) -> Result<Option<(Utf8PathBuf, &OpenRepository)>, napi::Error> {
let Some(workspace_folder) = vscode_sys::workspace::get_workspace_folder(env, uri)? else {
tracing::debug!(
message = "URI does not correspond to a workspace folder",
uri = ?uri.to_string()
);
return Ok(None);
};
let workspace_uri = workspace_folder.get_uri()?;
let workspace_path = Utf8PathBuf::from(workspace_uri.get_fs_path()?);
Ok(self
.repositories
.get(&workspace_path)
.map(|open_repository| (workspace_path, open_repository)))
}
#[tracing::instrument(skip_all)]
pub fn get_open_repository_mut(
&mut self,
env: &napi::Env,
uri: &vscode_sys::Uri,
) -> Result<Option<(Utf8PathBuf, &mut OpenRepository)>, napi::Error> {
let Some(workspace_folder) = vscode_sys::workspace::get_workspace_folder(env, uri)? else {
tracing::debug!(
message = "URI does not correspond to a workspace folder",
uri = ?uri.to_string()
);
return Ok(None);
};
let workspace_uri = workspace_folder.get_uri()?;
let workspace_path = Utf8PathBuf::from(workspace_uri.get_fs_path()?);
Ok(self
.repositories
.get_mut(&workspace_path)
.map(|open_repository| (workspace_path, open_repository)))
}
pub fn register_text_editors(
&mut self,
env: &napi::Env,
text_editors: Vec<vscode_sys::TextEditor>,
) -> Result<(), napi::Error> {
for text_editor in text_editors {
let document = text_editor.get_document()?;
let uri = document.get_uri()?;
if let Some((repository_path, open_repository)) =
self.get_open_repository_mut(env, &uri)?
{
let absolute_editor_path = Utf8PathBuf::from(uri.get_fs_path()?);
let relative_editor_path = absolute_editor_path
.strip_prefix(&repository_path)
.unwrap()
.to_path_buf();
open_repository.register_text_editor(relative_editor_path, text_editor)?;
tracing::debug!(
message = "Registered text editor",
?repository_path,
uri = uri.to_string()?
);
} else {
tracing::debug!(
message = "Ignoring text editor without valid workspace",
uri = uri.to_string()?
);
}
}
Ok(())
}
#[tracing::instrument(skip_all)]
pub fn open_workspace_folder(
&mut self,
env: &napi::Env,
workspace_folder: vscode_sys::WorkspaceFolder,
) -> Result<(), napi::Error> {
let repository_uri = workspace_folder.get_uri()?;
let repository_path = Utf8PathBuf::from(repository_uri.get_fs_path()?);
let open_repository = OpenRepository::new(env, &repository_uri)?;
if self
.repositories
.try_insert(repository_path.clone(), open_repository)
.is_err()
{
tracing::error!(
message = "Failed to insert duplicate repository",
?repository_path
);
}
Ok(())
}
#[tracing::instrument(skip_all)]
pub fn close_workspace_folder(
&mut self,
workspace_folder: vscode_sys::WorkspaceFolder,
) -> Result<(), napi::Error> {
let repository_uri = workspace_folder.get_uri()?;
let repository_path = Utf8PathBuf::from(repository_uri.get_fs_path()?);
if self.repositories.remove(&repository_path).is_none() {
tracing::error!(
message = "Failed to remove repository that does not exist",
?repository_path
);
}
Ok(())
}
#[tracing::instrument(skip_all)]
pub fn iter_repositories(&self) -> impl Iterator<Item = (&Utf8PathBuf, &OpenRepository)> {
self.repositories.iter()
}
}