use std::path::PathBuf;
use lsp_types::{
DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
DidSaveTextDocumentParams,
};
use crate::context::{AnalysisState, ServerContextSnapshot, UpdateEvent};
use crate::util::uri_to_file_path;
pub async fn on_did_open_text_document(
context: ServerContextSnapshot,
params: DidOpenTextDocumentParams,
) -> Option<()> {
context.enqueue(UpdateEvent::Opened(params)).await;
Some(())
}
pub async fn process_did_open_text_document(
context: ServerContextSnapshot,
params: DidOpenTextDocumentParams,
) -> Option<()> {
let uri = params.text_document.uri;
let version = params.text_document.version;
let text = params.text_document.text;
let path = uri_to_file_path(&uri)?;
let open_single_file_workspace = {
let mut workspace_manager = context.workspace_manager().lock().await;
workspace_manager.open_file(uri.clone(), text.clone(), version);
if workspace_manager.root().is_none() {
if let Some(parent) = path.parent() {
workspace_manager.set_roots(vec![parent.to_path_buf()]);
true
} else {
log::warn!("cannot choose a workspace for {}", path.display());
false
}
} else {
false
}
};
if open_single_file_workspace {
crate::handlers::start_analysis(context.clone()).await;
crate::handlers::register_files_watch(context.clone()).await;
}
apply_buffer(&context, path, text).await;
context
.diagnostics()
.schedule_open_files(context.clone())
.await;
Some(())
}
pub async fn on_did_change_text_document(
context: ServerContextSnapshot,
params: DidChangeTextDocumentParams,
) -> Option<()> {
context.enqueue(UpdateEvent::Changed(params)).await;
Some(())
}
pub async fn process_did_change_text_document(
context: ServerContextSnapshot,
params: DidChangeTextDocumentParams,
) -> Option<()> {
let uri = params.text_document.uri;
let version = params.text_document.version;
let path = uri_to_file_path(&uri)?;
let text = {
let mut workspace_manager = context.workspace_manager().lock().await;
match workspace_manager.change_file(&uri, version, ¶ms.content_changes) {
Ok(text) => text,
Err(error) => {
log::warn!("cannot apply document change for {}: {error}", uri.as_str());
return None;
}
}
};
apply_buffer(&context, path, text).await;
context
.diagnostics()
.schedule_open_files(context.clone())
.await;
Some(())
}
pub async fn on_did_save_text_document(
context: ServerContextSnapshot,
params: DidSaveTextDocumentParams,
) -> Option<()> {
context.enqueue(UpdateEvent::Saved(params)).await;
Some(())
}
pub async fn process_did_save_text_document(
context: ServerContextSnapshot,
params: DidSaveTextDocumentParams,
) -> Option<()> {
let text = params.text?;
let uri = params.text_document.uri;
let path = uri_to_file_path(&uri)?;
{
let mut workspace_manager = context.workspace_manager().lock().await;
if let Err(error) = workspace_manager.replace_open_text(&uri, text.clone()) {
log::warn!("cannot apply saved text for {}: {error}", uri.as_str());
return None;
}
}
apply_buffer(&context, path, text).await;
context
.diagnostics()
.schedule_open_files(context.clone())
.await;
Some(())
}
pub async fn on_did_close_document(
context: ServerContextSnapshot,
params: DidCloseTextDocumentParams,
) -> Option<()> {
context.enqueue(UpdateEvent::Closed(params)).await;
Some(())
}
pub async fn process_did_close_document(
context: ServerContextSnapshot,
params: DidCloseTextDocumentParams,
) -> Option<()> {
let uri = params.text_document.uri;
{
let mut workspace_manager = context.workspace_manager().lock().await;
workspace_manager.close_open_file(&uri);
}
context
.diagnostics()
.close_document(&context, uri.clone())
.await;
let Some(path) = uri_to_file_path(&uri) else {
return Some(());
};
context
.analysis()
.update_session("didClose", |session| session.did_close(&path))
.await;
context.analysis().wake();
context
.diagnostics()
.schedule_open_files(context.clone())
.await;
Some(())
}
async fn apply_buffer(context: &ServerContextSnapshot, path: PathBuf, text: String) {
let analysis: &AnalysisState = context.analysis();
let for_session = path.clone();
let applied = analysis
.update_session("didOpen", move |session| {
session.did_open(&for_session, &text);
})
.await;
if applied.is_none() {
log::debug!("no analysis yet: the buffer is held until a workspace root is named");
return;
}
analysis.wake();
}