Detailed changes
@@ -7,7 +7,7 @@ use crate::lsp_ext::find_specific_language_server_in_selection;
use crate::{element::register_action, Editor, SwitchSourceHeader};
-const CLANGD_SERVER_NAME: &str = "clangd";
+use project::lsp_store::clangd_ext::CLANGD_SERVER_NAME;
fn is_c_language(language: &Language) -> bool {
return language.name() == "C++".into() || language.name() == "C".into();
@@ -46,7 +46,7 @@ pub fn switch_source_header(
project.request_lsp(
buffer,
project::LanguageServerToQuery::Other(server_to_query),
- project::lsp_ext_command::SwitchSourceHeader,
+ project::lsp_store::lsp_ext_command::SwitchSourceHeader,
cx,
)
});
@@ -4,7 +4,7 @@ use anyhow::Context as _;
use gpui::{App, AppContext as _, Context, Entity, Window};
use language::{Capability, Language};
use multi_buffer::MultiBuffer;
-use project::lsp_ext_command::ExpandMacro;
+use project::lsp_store::{lsp_ext_command::ExpandMacro, rust_analyzer_ext::RUST_ANALYZER_NAME};
use text::ToPointUtf16;
use crate::{
@@ -12,8 +12,6 @@ use crate::{
ExpandMacroRecursively, OpenDocs,
};
-const RUST_ANALYZER_NAME: &str = "rust-analyzer";
-
fn is_rust_language(language: &Language) -> bool {
language.name() == "Rust".into()
}
@@ -131,7 +129,7 @@ pub fn open_docs(editor: &mut Editor, _: &OpenDocs, window: &mut Window, cx: &mu
project.request_lsp(
buffer,
project::LanguageServerToQuery::Other(server_to_query),
- project::lsp_ext_command::OpenDocs { position },
+ project::lsp_store::lsp_ext_command::OpenDocs { position },
cx,
)
});
@@ -278,6 +278,9 @@ impl super::LspAdapter for CLspAdapter {
"textDocument": {
"completion" : {
"editsNearCursor": true
+ },
+ "inactiveRegionsCapabilities": {
+ "inactiveRegions": true,
}
}
});
@@ -299,34 +299,6 @@ pub struct AdapterServerCapabilities {
pub code_action_kinds: Option<Vec<CodeActionKind>>,
}
-/// Experimental: Informs the end user about the state of the server
-///
-/// [Rust Analyzer Specification](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#server-status)
-#[derive(Debug)]
-pub enum ServerStatus {}
-
-/// Other(String) variant to handle unknown values due to this still being experimental
-#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
-#[serde(rename_all = "camelCase")]
-pub enum ServerHealthStatus {
- Ok,
- Warning,
- Error,
- Other(String),
-}
-
-#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
-#[serde(rename_all = "camelCase")]
-pub struct ServerStatusParams {
- pub health: ServerHealthStatus,
- pub message: Option<String>,
-}
-
-impl lsp_types::notification::Notification for ServerStatus {
- type Params = ServerStatusParams;
- const METHOD: &'static str = "experimental/serverStatus";
-}
-
impl LanguageServer {
/// Starts a language server process.
#[allow(clippy::too_many_arguments)]
@@ -1,9 +1,12 @@
+pub mod clangd_ext;
+pub mod lsp_ext_command;
+pub mod rust_analyzer_ext;
+
use crate::{
buffer_store::{BufferStore, BufferStoreEvent},
deserialize_code_actions,
environment::ProjectEnvironment,
lsp_command::{self, *},
- lsp_ext_command,
prettier_store::{self, PrettierStore, PrettierStoreEvent},
project_settings::{LspSettings, ProjectSettings},
project_tree::{AdapterQuery, LanguageServerTree, LaunchDisposition, ProjectTree},
@@ -48,8 +51,8 @@ use lsp::{
FileOperationPatternKind, FileOperationRegistrationOptions, FileRename, FileSystemWatcher,
InsertTextFormat, LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions,
LanguageServerId, LanguageServerName, LspRequestFuture, MessageActionItem, MessageType, OneOf,
- RenameFilesParams, ServerHealthStatus, ServerStatus, SymbolKind, TextEdit, WillRenameFiles,
- WorkDoneProgressCancelParams, WorkspaceFolder,
+ RenameFilesParams, SymbolKind, TextEdit, WillRenameFiles, WorkDoneProgressCancelParams,
+ WorkspaceFolder,
};
use node_runtime::read_package_installed_version;
use parking_lot::Mutex;
@@ -841,50 +844,6 @@ impl LocalLspStore {
}
})
.detach();
-
- language_server
- .on_notification::<ServerStatus, _>({
- let this = this.clone();
- let name = name.to_string();
- move |params, mut cx| {
- let this = this.clone();
- let name = name.to_string();
- if let Some(ref message) = params.message {
- let message = message.trim();
- if !message.is_empty() {
- let formatted_message = format!(
- "Language server {name} (id {server_id}) status update: {message}"
- );
- match params.health {
- ServerHealthStatus::Ok => log::info!("{}", formatted_message),
- ServerHealthStatus::Warning => log::warn!("{}", formatted_message),
- ServerHealthStatus::Error => {
- log::error!("{}", formatted_message);
- let (tx, _rx) = smol::channel::bounded(1);
- let request = LanguageServerPromptRequest {
- level: PromptLevel::Critical,
- message: params.message.unwrap_or_default(),
- actions: Vec::new(),
- response_channel: tx,
- lsp_name: name.clone(),
- };
- let _ = this
- .update(&mut cx, |_, cx| {
- cx.emit(LspStoreEvent::LanguageServerPrompt(request));
- })
- .ok();
- }
- ServerHealthStatus::Other(status) => {
- log::info!(
- "Unknown server health: {status}\n{formatted_message}"
- )
- }
- }
- }
- }
- }
- })
- .detach();
language_server
.on_notification::<lsp::notification::ShowMessage, _>({
let this = this.clone();
@@ -970,6 +929,9 @@ impl LocalLspStore {
}
})
.detach();
+
+ rust_analyzer_ext::register_notifications(this.clone(), language_server);
+ clangd_ext::register_notifications(this, language_server, adapter);
}
fn shutdown_language_servers(
@@ -0,0 +1,75 @@
+use std::sync::Arc;
+
+use ::serde::{Deserialize, Serialize};
+use gpui::WeakEntity;
+use language::CachedLspAdapter;
+use lsp::LanguageServer;
+use util::ResultExt as _;
+
+use crate::LspStore;
+
+pub const CLANGD_SERVER_NAME: &str = "clangd";
+
+#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct InactiveRegionsParams {
+ pub text_document: lsp::OptionalVersionedTextDocumentIdentifier,
+ pub regions: Vec<lsp::Range>,
+}
+
+/// InactiveRegions is a clangd extension that marks regions of inactive code.
+pub struct InactiveRegions;
+
+impl lsp::notification::Notification for InactiveRegions {
+ type Params = InactiveRegionsParams;
+ const METHOD: &'static str = "textDocument/inactiveRegions";
+}
+
+pub fn register_notifications(
+ lsp_store: WeakEntity<LspStore>,
+ language_server: &LanguageServer,
+ adapter: Arc<CachedLspAdapter>,
+) {
+ if language_server.name().0 != CLANGD_SERVER_NAME {
+ return;
+ }
+ let server_id = language_server.server_id();
+
+ language_server
+ .on_notification::<InactiveRegions, _>({
+ let adapter = adapter.clone();
+ let this = lsp_store;
+
+ move |params: InactiveRegionsParams, mut cx| {
+ let adapter = adapter.clone();
+ this.update(&mut cx, |this, cx| {
+ let diagnostics = params
+ .regions
+ .into_iter()
+ .map(|range| lsp::Diagnostic {
+ range,
+ severity: Some(lsp::DiagnosticSeverity::INFORMATION),
+ source: Some(CLANGD_SERVER_NAME.to_string()),
+ message: "inactive region".to_string(),
+ tags: Some(vec![lsp::DiagnosticTag::UNNECESSARY]),
+ ..Default::default()
+ })
+ .collect();
+ let mapped_diagnostics = lsp::PublishDiagnosticsParams {
+ uri: params.text_document.uri,
+ version: params.text_document.version,
+ diagnostics,
+ };
+ this.update_diagnostics(
+ server_id,
+ mapped_diagnostics,
+ &adapter.disk_based_diagnostic_sources,
+ cx,
+ )
+ .log_err();
+ })
+ .ok();
+ }
+ })
+ .detach();
+}
@@ -0,0 +1,83 @@
+use ::serde::{Deserialize, Serialize};
+use gpui::{PromptLevel, WeakEntity};
+use lsp::LanguageServer;
+
+use crate::{LanguageServerPromptRequest, LspStore, LspStoreEvent};
+
+pub const RUST_ANALYZER_NAME: &str = "rust-analyzer";
+
+/// Experimental: Informs the end user about the state of the server
+///
+/// [Rust Analyzer Specification](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#server-status)
+#[derive(Debug)]
+enum ServerStatus {}
+
+/// Other(String) variant to handle unknown values due to this still being experimental
+#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
+#[serde(rename_all = "camelCase")]
+enum ServerHealthStatus {
+ Ok,
+ Warning,
+ Error,
+ Other(String),
+}
+
+#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
+#[serde(rename_all = "camelCase")]
+struct ServerStatusParams {
+ pub health: ServerHealthStatus,
+ pub message: Option<String>,
+}
+
+impl lsp::notification::Notification for ServerStatus {
+ type Params = ServerStatusParams;
+ const METHOD: &'static str = "experimental/serverStatus";
+}
+
+pub fn register_notifications(lsp_store: WeakEntity<LspStore>, language_server: &LanguageServer) {
+ let name = language_server.name();
+ let server_id = language_server.server_id();
+
+ let this = lsp_store;
+
+ language_server
+ .on_notification::<ServerStatus, _>({
+ let name = name.to_string();
+ move |params, mut cx| {
+ let this = this.clone();
+ let name = name.to_string();
+ if let Some(ref message) = params.message {
+ let message = message.trim();
+ if !message.is_empty() {
+ let formatted_message = format!(
+ "Language server {name} (id {server_id}) status update: {message}"
+ );
+ match params.health {
+ ServerHealthStatus::Ok => log::info!("{}", formatted_message),
+ ServerHealthStatus::Warning => log::warn!("{}", formatted_message),
+ ServerHealthStatus::Error => {
+ log::error!("{}", formatted_message);
+ let (tx, _rx) = smol::channel::bounded(1);
+ let request = LanguageServerPromptRequest {
+ level: PromptLevel::Critical,
+ message: params.message.unwrap_or_default(),
+ actions: Vec::new(),
+ response_channel: tx,
+ lsp_name: name.clone(),
+ };
+ let _ = this
+ .update(&mut cx, |_, cx| {
+ cx.emit(LspStoreEvent::LanguageServerPrompt(request));
+ })
+ .ok();
+ }
+ ServerHealthStatus::Other(status) => {
+ log::info!("Unknown server health: {status}\n{formatted_message}")
+ }
+ }
+ }
+ }
+ }
+ })
+ .detach();
+}
@@ -5,7 +5,6 @@ pub mod debounced_delay;
pub mod git;
pub mod image_store;
pub mod lsp_command;
-pub mod lsp_ext_command;
pub mod lsp_store;
pub mod prettier_store;
pub mod project_settings;