use super::{
ApiClient, ApiSpawnConfig, DocumentIdentifier, FileChanges, ManagedSnapshot, NodeHandle,
OverlayChanges, ProjectHandle, ProjectResponse, SignatureHandle, SignatureResponse,
SymbolHandle, SymbolResponse, TypeHandle, TypeResponse, UpdateSnapshotParams,
};
use crate::{CorsaError, Result};
pub struct ProjectSession {
client: ApiClient,
snapshot: ManagedSnapshot,
project: ProjectResponse,
open_project: String,
preferred_document: Option<DocumentIdentifier>,
}
impl ProjectSession {
pub async fn spawn(
config: ApiSpawnConfig,
open_project: impl Into<String>,
preferred_document: Option<DocumentIdentifier>,
) -> Result<Self> {
let client = ApiClient::spawn(config).await?;
Self::open(client, open_project, preferred_document).await
}
pub async fn open(
client: ApiClient,
open_project: impl Into<String>,
preferred_document: Option<DocumentIdentifier>,
) -> Result<Self> {
let open_project = open_project.into();
let snapshot = client
.update_snapshot(UpdateSnapshotParams {
open_project: Some(open_project.clone()),
file_changes: None,
overlay_changes: None,
})
.await?;
let project = resolve_project(&snapshot, preferred_document.as_ref()).await?;
Ok(Self {
client,
snapshot,
project,
open_project,
preferred_document,
})
}
pub async fn refresh(&mut self, file_changes: Option<FileChanges>) -> Result<()> {
self.refresh_with_params(UpdateSnapshotParams {
open_project: None,
file_changes,
overlay_changes: None,
})
.await
}
pub async fn refresh_with_params(&mut self, params: UpdateSnapshotParams) -> Result<()> {
let open_project = params
.open_project
.unwrap_or_else(|| self.open_project.clone());
let snapshot = self
.client
.update_snapshot(UpdateSnapshotParams {
open_project: Some(open_project.clone()),
file_changes: params.file_changes,
overlay_changes: params.overlay_changes,
})
.await?;
let project = resolve_project(&snapshot, self.preferred_document.as_ref()).await?;
self.snapshot = snapshot;
self.project = project;
self.open_project = open_project;
Ok(())
}
pub async fn refresh_with_overlay_changes(
&mut self,
file_changes: Option<FileChanges>,
overlay_changes: Option<OverlayChanges>,
) -> Result<()> {
self.refresh_with_params(UpdateSnapshotParams {
open_project: None,
file_changes,
overlay_changes,
})
.await?;
Ok(())
}
pub async fn close(&self) -> Result<()> {
self.client.close().await
}
pub fn client(&self) -> &ApiClient {
&self.client
}
pub fn project(&self) -> &ProjectResponse {
&self.project
}
pub fn snapshot(&self) -> &ManagedSnapshot {
&self.snapshot
}
pub fn project_handle(&self) -> ProjectHandle {
self.project.id.clone()
}
pub async fn get_symbol_at_position(
&self,
file: impl Into<DocumentIdentifier>,
position: u32,
) -> Result<Option<SymbolResponse>> {
self.client
.get_symbol_at_position(
self.snapshot.handle.clone(),
self.project.id.clone(),
file,
position,
)
.await
}
pub async fn get_type_at_position(
&self,
file: impl Into<DocumentIdentifier>,
position: u32,
) -> Result<Option<TypeResponse>> {
self.client
.get_type_at_position(
self.snapshot.handle.clone(),
self.project.id.clone(),
file,
position,
)
.await
}
pub async fn get_type_of_symbol(&self, symbol: SymbolHandle) -> Result<Option<TypeResponse>> {
self.client
.get_type_of_symbol(
self.snapshot.handle.clone(),
self.project.id.clone(),
symbol,
)
.await
}
pub async fn get_types_of_symbols(
&self,
symbols: Vec<SymbolHandle>,
) -> Result<Vec<Option<TypeResponse>>> {
self.client
.get_types_of_symbols(
self.snapshot.handle.clone(),
self.project.id.clone(),
symbols,
)
.await
}
pub async fn get_properties_of_type(&self, r#type: TypeHandle) -> Result<Vec<SymbolResponse>> {
self.client
.get_properties_of_type(
self.snapshot.handle.clone(),
self.project.id.clone(),
r#type,
)
.await
}
pub async fn get_signatures_of_type(
&self,
r#type: TypeHandle,
kind: i32,
) -> Result<Vec<SignatureResponse>> {
self.client
.get_signatures_of_type(
self.snapshot.handle.clone(),
self.project.id.clone(),
r#type,
kind,
)
.await
}
pub async fn get_return_type_of_signature(
&self,
signature: SignatureHandle,
) -> Result<Option<TypeResponse>> {
self.client
.get_return_type_of_signature(
self.snapshot.handle.clone(),
self.project.id.clone(),
signature,
)
.await
}
pub async fn type_to_string(
&self,
r#type: TypeHandle,
enclosing: Option<NodeHandle>,
flags: Option<i32>,
) -> Result<String> {
self.client
.type_to_string(
self.snapshot.handle.clone(),
self.project.id.clone(),
r#type,
enclosing,
flags,
)
.await
}
}
async fn resolve_project(
snapshot: &ManagedSnapshot,
preferred_document: Option<&DocumentIdentifier>,
) -> Result<ProjectResponse> {
if let Some(document) = preferred_document {
if let Some(project) = snapshot
.get_default_project_for_file(document.clone())
.await?
{
return Ok(project);
}
}
snapshot
.projects
.first()
.cloned()
.ok_or_else(|| CorsaError::Protocol("project session did not resolve a project".into()))
}