Skip to content

Commit

Permalink
lsp: add struct for LSP pull-based diagnostics
Browse files Browse the repository at this point in the history
  • Loading branch information
vitallium committed Dec 3, 2024
1 parent e83d2ff commit 9de1d98
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 27 deletions.
8 changes: 4 additions & 4 deletions crates/editor/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ use project::{
lsp_store::{FormatTarget, FormatTrigger},
project_settings::{GitGutterSetting, ProjectSettings},
CodeAction, Completion, CompletionIntent, DocumentHighlight, InlayHint, Location, LocationLink,
Project, ProjectItem, ProjectTransaction, TaskSourceKind,
LspDiagnostics, Project, ProjectItem, ProjectTransaction, TaskSourceKind,
};
use rand::prelude::*;
use rpc::{proto::*, ErrorExt};
Expand Down Expand Up @@ -10909,7 +10909,7 @@ impl Editor {

editor
.update(&mut cx, |_, cx| {
project.diagnostics(&start_buffer, start, cx);
project.diagnostics(&start_buffer, start, cx)
})
.ok();
});
Expand Down Expand Up @@ -13789,7 +13789,7 @@ pub trait DiagnosticsProvider {
buffer: &Model<Buffer>,
position: text::Anchor,
cx: &mut WindowContext,
) -> Option<Task<Result<Vec<lsp::Diagnostic>>>>;
) -> Option<Task<Result<Vec<LspDiagnostics>>>>;
}

impl CodeActionProvider for Model<Project> {
Expand Down Expand Up @@ -14080,7 +14080,7 @@ impl DiagnosticsProvider for Model<Project> {
buffer: &Model<Buffer>,
position: text::Anchor,
cx: &mut WindowContext,
) -> Option<Task<Result<Vec<lsp::Diagnostic>>>> {
) -> Option<Task<Result<Vec<LspDiagnostics>>>> {
Some(self.update(cx, |project, cx| {
project.document_diagnostics(buffer, position, cx)
}))
Expand Down
112 changes: 102 additions & 10 deletions crates/project/src/lsp_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ mod signature_help;
use crate::{
lsp_store::LspStore, CodeAction, CoreCompletion, DocumentHighlight, Hover, HoverBlock,
HoverBlockKind, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintLabelPartTooltip,
InlayHintTooltip, Location, LocationLink, MarkupContent, ProjectTransaction, ResolveState,
InlayHintTooltip, Location, LocationLink, LspDiagnostics, MarkupContent, ProjectTransaction,
ResolveState,
};
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
Expand All @@ -21,12 +22,13 @@ use language::{
};
use lsp::{
AdapterServerCapabilities, CodeActionKind, CodeActionOptions, CompletionContext,
CompletionListItemDefaultsEditRange, CompletionTriggerKind, Diagnostic, DocumentHighlightKind,
CompletionListItemDefaultsEditRange, CompletionTriggerKind, DocumentHighlightKind,
LanguageServer, LanguageServerId, LinkedEditingRangeServerCapabilities, OneOf,
ServerCapabilities,
};
use serde_json::Value;
use signature_help::{lsp_to_proto_signature, proto_to_lsp_signature};
use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
use std::{cmp::Reverse, ops::Range, path::Path, str::FromStr, sync::Arc};
use text::{BufferId, LineEnding};

pub use signature_help::{
Expand Down Expand Up @@ -3075,9 +3077,92 @@ impl LspCommand for LinkedEditingRange {
}
}

impl GetDocumentDiagnostics {
pub fn deserialize_lsp_diagnostic(diagnostic: proto::LspDiagnostic) -> lsp::Diagnostic {
let start = diagnostic.start.unwrap();
let end = diagnostic.end.unwrap();

let range = Range::<PointUtf16> {
start: PointUtf16 {
row: start.row,
column: start.column,
},
end: PointUtf16 {
row: end.row,
column: end.column,
},
};

let data = if let Some(data) = diagnostic.data {
Value::from_str(&data).ok()
} else {
None
};

let code = if let Some(code) = diagnostic.code {
Some(lsp::NumberOrString::String(code))
} else {
None
};

lsp::Diagnostic {
range: language::range_to_lsp(range),
severity: match proto::lsp_diagnostic::Severity::from_i32(diagnostic.severity).unwrap()
{
proto::lsp_diagnostic::Severity::Error => Some(lsp::DiagnosticSeverity::ERROR),
proto::lsp_diagnostic::Severity::Warning => Some(lsp::DiagnosticSeverity::WARNING),
proto::lsp_diagnostic::Severity::Information => {
Some(lsp::DiagnosticSeverity::INFORMATION)
}
proto::lsp_diagnostic::Severity::Hint => Some(lsp::DiagnosticSeverity::HINT),
_ => None,
},
code,
// FIXME
code_description: None,
related_information: Some(vec![]),
tags: Some(vec![]),
source: diagnostic.source.clone(),
message: diagnostic.message,
data,
}
}

pub fn serialize_lsp_diagnostic(diagnostic: lsp::Diagnostic) -> proto::LspDiagnostic {
let range = language::range_from_lsp(diagnostic.range);

proto::LspDiagnostic {
start: Some(proto::PointUtf16 {
row: range.start.0.row,
column: range.start.0.column,
}),
end: Some(proto::PointUtf16 {
row: range.end.0.row,
column: range.end.0.column,
}),
severity: match diagnostic.severity {
Some(lsp::DiagnosticSeverity::ERROR) => proto::lsp_diagnostic::Severity::Error,
Some(lsp::DiagnosticSeverity::WARNING) => proto::lsp_diagnostic::Severity::Warning,
Some(lsp::DiagnosticSeverity::INFORMATION) => {
proto::lsp_diagnostic::Severity::Information
}
Some(lsp::DiagnosticSeverity::HINT) => proto::lsp_diagnostic::Severity::Hint,
_ => proto::lsp_diagnostic::Severity::None,
} as i32,
code: diagnostic.code.as_ref().map(|code| match code {
lsp::NumberOrString::Number(code) => code.to_string(),
lsp::NumberOrString::String(code) => code.clone(),
}),
source: diagnostic.source.clone(),
message: diagnostic.message,
data: diagnostic.data.as_ref().map(|data| data.to_string()),
}
}
}

#[async_trait(?Send)]
impl LspCommand for GetDocumentDiagnostics {
type Response = Option<Vec<Diagnostic>>;
type Response = LspDiagnostics;
type LspRequest = lsp::request::DocumentDiagnosticRequest;
type ProtoRequest = proto::GetDocumentDiagnostics;

Expand Down Expand Up @@ -3119,17 +3204,24 @@ impl LspCommand for GetDocumentDiagnostics {
message: lsp::DocumentDiagnosticReportResult,
_: Model<LspStore>,
_: Model<Buffer>,
_: LanguageServerId,
server_id: LanguageServerId,
_: AsyncAppContext,
) -> Result<Self::Response> {
match message {
lsp::DocumentDiagnosticReportResult::Report(report) => match report {
lsp::DocumentDiagnosticReport::Full(report) => {
Ok(Some(report.full_document_diagnostic_report.items.clone()))
}
lsp::DocumentDiagnosticReport::Unchanged(_) => Ok(None),
lsp::DocumentDiagnosticReport::Full(report) => Ok(LspDiagnostics {
server_id,
diagnostics: Some(report.full_document_diagnostic_report.items.clone()),
}),
lsp::DocumentDiagnosticReport::Unchanged(_) => Ok(LspDiagnostics {
server_id,
diagnostics: None,
}),
},
lsp::DocumentDiagnosticReportResult::Partial(_) => Ok(None),
lsp::DocumentDiagnosticReportResult::Partial(_) => Ok(LspDiagnostics {
server_id,
diagnostics: None,
}),
}
}

Expand Down
16 changes: 5 additions & 11 deletions crates/project/src/lsp_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ use crate::{
toolchain_store::{EmptyToolchainStore, ToolchainStoreEvent},
worktree_store::{WorktreeStore, WorktreeStoreEvent},
yarn::YarnPathStore,
CodeAction, Completion, CoreCompletion, Hover, InlayHint, ProjectItem as _, ProjectPath,
ProjectTransaction, ResolveState, Symbol, ToolchainStore,
CodeAction, Completion, CoreCompletion, Hover, InlayHint, ProjectItem as _,
LspDiagnostics, ProjectPath, ProjectTransaction, ResolveState, Symbol,
ToolchainStore,
};
use anyhow::{anyhow, Context as _, Result};
use async_trait::async_trait;
Expand Down Expand Up @@ -3163,7 +3164,7 @@ impl LspStore {
buffer_handle: &Model<Buffer>,
position: Anchor,
cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<lsp::Diagnostic>>> {
) -> Task<Result<Vec<LspDiagnostics>>> {
let buffer = buffer_handle.read(cx);
let buffer_id = buffer.remote_id();

Expand Down Expand Up @@ -3213,7 +3214,6 @@ impl LspStore {
.into_iter()
.collect::<Result<Vec<_>>>()?
.into_iter()
.flat_map(|diagnostics| diagnostics.into_iter().flatten())
.collect())
})
} else {
Expand All @@ -3223,13 +3223,7 @@ impl LspStore {
GetDocumentDiagnostics { position },
cx,
);
cx.spawn(|_, _| async move {
Ok(all_actions_task
.await
.into_iter()
.flat_map(|diagnostics| diagnostics.into_iter().flatten())
.collect())
})
cx.spawn(|_, _| async move { Ok(all_actions_task.await.into_iter().collect()) })
}
}

Expand Down
20 changes: 19 additions & 1 deletion crates/project/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,24 @@ pub const DEFAULT_COMPLETION_CONTEXT: CompletionContext = CompletionContext {
trigger_character: None,
};

/// An LSP diagnostics associated with a certain language server.
#[derive(Clone, Debug)]
pub struct LspDiagnostics {
/// The id of the language server that produced this code action.
pub server_id: LanguageServerId,
/// The diagnostics produced by this language server.
pub diagnostics: Option<Vec<lsp::Diagnostic>>,
}

impl std::default::Default for LspDiagnostics {
fn default() -> Self {
Self {
server_id: LanguageServerId(0),
diagnostics: None,
}
}
}

impl Project {
pub fn init_settings(cx: &mut AppContext) {
WorktreeSettings::register(cx);
Expand Down Expand Up @@ -2964,7 +2982,7 @@ impl Project {
buffer_handle: &Model<Buffer>,
position: Anchor,
cx: &mut ModelContext<Self>,
) -> Task<anyhow::Result<Vec<lsp::Diagnostic>>> {
) -> Task<anyhow::Result<Vec<LspDiagnostics>>> {
self.lsp_store.update(cx, |lsp_store, cx| {
lsp_store.document_diagnostic(buffer_handle, position, cx)
})
Expand Down
34 changes: 33 additions & 1 deletion crates/proto/proto/zed.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2575,6 +2575,37 @@ message InstallExtension {
string tmp_dir = 2;
}

message LspDiagnosticRelatedInformation {
string location = 1;
string message = 2;
}

message LspDiagnosticTag {
string name = 1;
optional string value = 2;
}

message LspDiagnostic {
PointUtf16 start = 1;
PointUtf16 end = 2;
Severity severity = 3;
optional string code = 4;
// optional string code_description = 5;
optional string source = 6;
string message = 7;
// repeated LspDiagnosticRelatedInformation related_information = 8;
// repeated LspDiagnosticTag tags = 9;
optional string data = 10;

enum Severity {
None = 0;
Error = 1;
Warning = 2;
Information = 3;
Hint = 4;
}
}

message GetDocumentDiagnostics {
uint64 project_id = 1;
uint64 buffer_id = 2;
Expand All @@ -2583,5 +2614,6 @@ message GetDocumentDiagnostics {
}

message GetDocumentDiagnosticsResponse {
repeated Diagnostic diagnostics = 1;
uint64 server_id = 1;
repeated LspDiagnostic diagnostics = 2;
}

0 comments on commit 9de1d98

Please sign in to comment.