use {
crate::{
Uri,
database::{
PartitionKey,
PartitionWriteContextRef,
},
protocol::{
jsonrpc,
lsp::{
Diagnostic,
PartialResultParams,
StaticRegistrationOptions,
TextDocumentIdentifier,
TextDocumentRegistrationOptions,
WorkDoneProgressOptions,
WorkDoneProgressParams,
},
},
record::LaburnumRecordRef,
scheduler::task::TaskContext,
},
serde::{
Deserialize,
Serialize,
},
std::collections::HashMap,
};
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DiagnosticClientCapabilities {
#[serde(skip_serializing_if = "Option::is_none")]
pub dynamic_registration: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub related_document_support: Option<bool>,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DiagnosticOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub identifier: Option<String>,
pub inter_file_dependencies: bool,
pub workspace_diagnostics: bool,
#[serde(flatten)]
pub work_done_progress_options: WorkDoneProgressOptions,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DiagnosticRegistrationOptions {
#[serde(flatten)]
pub text_document_registration_options: TextDocumentRegistrationOptions,
#[serde(flatten)]
pub diagnostic_options: DiagnosticOptions,
#[serde(flatten)]
pub static_registration_options: StaticRegistrationOptions,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum DiagnosticServerCapabilities {
Options(DiagnosticOptions),
RegistrationOptions(DiagnosticRegistrationOptions),
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DocumentDiagnosticParams {
pub text_document: TextDocumentIdentifier,
pub identifier: Option<String>,
pub previous_result_id: Option<String>,
#[serde(flatten)]
pub work_done_progress_params: WorkDoneProgressParams,
#[serde(flatten)]
pub partial_result_params: PartialResultParams,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FullDocumentDiagnosticReport {
#[serde(skip_serializing_if = "Option::is_none")]
pub result_id: Option<String>,
pub items: Vec<Diagnostic>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UnchangedDocumentDiagnosticReport {
pub result_id: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum DocumentDiagnosticReportKind {
Full(FullDocumentDiagnosticReport),
Unchanged(UnchangedDocumentDiagnosticReport),
}
impl From<FullDocumentDiagnosticReport> for DocumentDiagnosticReportKind {
fn from(from: FullDocumentDiagnosticReport) -> Self {
Self::Full(from)
}
}
impl From<UnchangedDocumentDiagnosticReport> for DocumentDiagnosticReportKind {
fn from(from: UnchangedDocumentDiagnosticReport) -> Self {
Self::Unchanged(from)
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RelatedFullDocumentDiagnosticReport {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub related_documents: Option<HashMap<Uri, DocumentDiagnosticReportKind>>,
#[serde(flatten)]
pub full_document_diagnostic_report: FullDocumentDiagnosticReport,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RelatedUnchangedDocumentDiagnosticReport {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub related_documents: Option<HashMap<Uri, DocumentDiagnosticReportKind>>,
#[serde(flatten)]
pub unchanged_document_diagnostic_report: UnchangedDocumentDiagnosticReport,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum DocumentDiagnosticReport {
Full(RelatedFullDocumentDiagnosticReport),
Unchanged(RelatedUnchangedDocumentDiagnosticReport),
}
impl From<RelatedFullDocumentDiagnosticReport> for DocumentDiagnosticReport {
fn from(from: RelatedFullDocumentDiagnosticReport) -> Self {
Self::Full(from)
}
}
impl From<RelatedUnchangedDocumentDiagnosticReport>
for DocumentDiagnosticReport
{
fn from(from: RelatedUnchangedDocumentDiagnosticReport) -> Self {
Self::Unchanged(from)
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DocumentDiagnosticReportPartialResult {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub related_documents: Option<HashMap<Uri, DocumentDiagnosticReportKind>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum DocumentDiagnosticReportResult {
Report(DocumentDiagnosticReport),
Partial(DocumentDiagnosticReportPartialResult),
}
impl From<DocumentDiagnosticReport> for DocumentDiagnosticReportResult {
fn from(from: DocumentDiagnosticReport) -> Self {
Self::Report(from)
}
}
impl From<DocumentDiagnosticReportPartialResult>
for DocumentDiagnosticReportResult
{
fn from(from: DocumentDiagnosticReportPartialResult) -> Self {
Self::Partial(from)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DiagnosticServerCancellationData {
pub retrigger_request: bool,
}
impl Default for DiagnosticServerCancellationData {
fn default() -> Self {
Self {
retrigger_request: true,
}
}
}
pub trait DiagnosticService<
P: crate::database::storage::Partitions,
T: crate::protocol::lsp::LanguageServer<P>,
>: Send + Sync + 'static
{
fn diagnostic(
&self,
params: DocumentDiagnosticParams,
ctx: &mut TaskContext<P, T>,
writer: &mut PartitionWriteContextRef<'_, P>,
) -> impl std::future::Future<
Output = jsonrpc::Result<DocumentDiagnosticReportResult>,
> + Send {
let _ = (self, writer);
let uri = params.text_document.uri.clone();
async move {
use crate::database::DynPartition;
let partition_key = crate::partitions::Diagnostics::KEY;
let query_client = ctx.query_client();
let query_results = query_client
.prefix_internal(partition_key, String::new())
.await;
let reader = ctx.source_cache_reader();
let requested_file_id = reader.get_file_id(&uri);
let encoding = ctx.position_encoding();
let lsp_diagnostics: Vec<Diagnostic> = query_results
.records()
.iter()
.filter_map(|record_meta| {
let record_ref = query_results.get(record_meta)?;
let diag = record_ref.as_dyn_diagnostic()?;
let source_key = diag.source_key()?;
if Some(source_key.file_id()) != requested_file_id {
return None;
}
Some(diag.to_lsp_diagnostic(&reader, &encoding))
})
.collect();
let report = RelatedFullDocumentDiagnosticReport {
related_documents: None,
full_document_diagnostic_report: FullDocumentDiagnosticReport {
result_id: None,
items: lsp_diagnostics,
},
};
Ok(DocumentDiagnosticReportResult::Report(
DocumentDiagnosticReport::Full(report),
))
}
}
const DIAGNOSTIC_LANE: crate::scheduler::lanes::Lane =
crate::scheduler::lanes::DEFAULT_LANE;
}