use lsp_types::{
Diagnostic, DocumentDiagnosticParams, DocumentDiagnosticReport, DocumentDiagnosticReportResult,
FullDocumentDiagnosticReport, RelatedFullDocumentDiagnosticReport,
};
use tokio_util::sync::CancellationToken;
use crate::context::{RequestOutcome, ServerContextSnapshot, snapshot_query};
use crate::util::uri_to_file_path;
pub async fn on_pull_document_diagnostic(
context: ServerContextSnapshot,
params: DocumentDiagnosticParams,
cancel_token: CancellationToken,
) -> RequestOutcome<DocumentDiagnosticReportResult> {
let uri = params.text_document.uri;
let Some(path) = uri_to_file_path(&uri) else {
return RequestOutcome::Ready(an_empty_report());
};
context.analysis().prepare_for_a_diagnostic(&path).await;
let for_the_query = path.clone();
let outcome = snapshot_query(context.analysis(), cancel_token, move |session| {
Some(super::diagnose_file(session, &for_the_query))
})
.await;
outcome.map(|found| {
let items = the_report(found.map(|(_, items)| items));
log::debug!("pull: {} -> {} item(s)", path.display(), items.len());
DocumentDiagnosticReport::Full(RelatedFullDocumentDiagnosticReport {
related_documents: None,
full_document_diagnostic_report: FullDocumentDiagnosticReport {
result_id: None,
items,
},
})
.into()
})
}
fn the_report(found: Option<Vec<Diagnostic>>) -> Vec<Diagnostic> {
found.unwrap_or_default()
}
fn an_empty_report() -> DocumentDiagnosticReportResult {
DocumentDiagnosticReport::Full(RelatedFullDocumentDiagnosticReport {
related_documents: None,
full_document_diagnostic_report: FullDocumentDiagnosticReport {
result_id: None,
items: Vec::new(),
},
})
.into()
}
#[cfg(test)]
mod tests {
use super::*;
fn a_diagnostic(message: &str) -> lsp_types::Diagnostic {
lsp_types::Diagnostic {
message: message.to_string(),
..lsp_types::Diagnostic::default()
}
}
#[test]
fn a_report_is_the_answer_for_the_text_that_is_there_now() {
assert!(
the_report(Some(Vec::new())).is_empty(),
"an empty answer is the answer: the file is clean"
);
assert!(
the_report(None).is_empty(),
"a pull that cannot answer says nothing, not the last thing it said"
);
let current = vec![a_diagnostic("a real finding")];
let sent = the_report(Some(current.clone()));
assert_eq!(sent.len(), 1);
assert_eq!(sent[0].message, current[0].message);
}
}