1use std::sync::Arc;
2
3use ::serde::{Deserialize, Serialize};
4use gpui::WeakEntity;
5use language::{CachedLspAdapter, Diagnostic};
6use lsp::LanguageServer;
7use util::ResultExt as _;
8
9use crate::LspStore;
10
11pub const CLANGD_SERVER_NAME: &str = "clangd";
12const INACTIVE_REGION_MESSAGE: &str = "inactive region";
13
14#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
15#[serde(rename_all = "camelCase")]
16pub struct InactiveRegionsParams {
17 pub text_document: lsp::OptionalVersionedTextDocumentIdentifier,
18 pub regions: Vec<lsp::Range>,
19}
20
21/// InactiveRegions is a clangd extension that marks regions of inactive code.
22pub struct InactiveRegions;
23
24impl lsp::notification::Notification for InactiveRegions {
25 type Params = InactiveRegionsParams;
26 const METHOD: &'static str = "textDocument/inactiveRegions";
27}
28
29pub fn is_inactive_region(diag: &Diagnostic) -> bool {
30 diag.is_unnecessary
31 && diag.severity == lsp::DiagnosticSeverity::INFORMATION
32 && diag.message == INACTIVE_REGION_MESSAGE
33 && diag
34 .source
35 .as_ref()
36 .is_some_and(|v| v == CLANGD_SERVER_NAME)
37}
38
39pub fn register_notifications(
40 lsp_store: WeakEntity<LspStore>,
41 language_server: &LanguageServer,
42 adapter: Arc<CachedLspAdapter>,
43) {
44 if language_server.name().0 != CLANGD_SERVER_NAME {
45 return;
46 }
47 let server_id = language_server.server_id();
48
49 language_server
50 .on_notification::<InactiveRegions, _>({
51 let adapter = adapter.clone();
52 let this = lsp_store;
53
54 move |params: InactiveRegionsParams, cx| {
55 let adapter = adapter.clone();
56 this.update(cx, |this, cx| {
57 let diagnostics = params
58 .regions
59 .into_iter()
60 .map(|range| lsp::Diagnostic {
61 range,
62 severity: Some(lsp::DiagnosticSeverity::INFORMATION),
63 source: Some(CLANGD_SERVER_NAME.to_string()),
64 message: INACTIVE_REGION_MESSAGE.to_string(),
65 tags: Some(vec![lsp::DiagnosticTag::UNNECESSARY]),
66 ..Default::default()
67 })
68 .collect();
69 let mapped_diagnostics = lsp::PublishDiagnosticsParams {
70 uri: params.text_document.uri,
71 version: params.text_document.version,
72 diagnostics,
73 };
74 this.merge_diagnostics(
75 server_id,
76 mapped_diagnostics,
77 &adapter.disk_based_diagnostic_sources,
78 |diag, _| !is_inactive_region(diag),
79 cx,
80 )
81 .log_err();
82 })
83 .ok();
84 }
85 })
86 .detach();
87}