mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
Enable configurable dismissal of language server notifications that do not require user interaction (#46708)
Closes #38769 Release Notes: - Dismiss server notifications automatically with `"global_lsp_settings": { "notifications": { "dismiss_timeout_ms": 5000 } }` settings defaults. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
parent
e9aadaf0af
commit
4bc3b710ee
8 changed files with 364 additions and 42 deletions
|
|
@ -2236,6 +2236,11 @@
|
|||
"global_lsp_settings": {
|
||||
// Whether to show the LSP servers button in the status bar.
|
||||
"button": true,
|
||||
"notifications": {
|
||||
// Timeout in milliseconds for automatically dismissing language server notifications.
|
||||
// Set to 0 to disable auto-dismiss.
|
||||
"dismiss_timeout_ms": 5000,
|
||||
},
|
||||
},
|
||||
// Jupyter settings
|
||||
"jupyter": {
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5
|
|||
pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
|
||||
const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
|
||||
const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
|
||||
pub enum ProgressToken {
|
||||
|
|
@ -1095,18 +1096,19 @@ impl LocalLspStore {
|
|||
async move {
|
||||
let actions = params.actions.unwrap_or_default();
|
||||
let message = params.message.clone();
|
||||
let (tx, rx) = smol::channel::bounded(1);
|
||||
let request = LanguageServerPromptRequest {
|
||||
level: match params.typ {
|
||||
lsp::MessageType::ERROR => PromptLevel::Critical,
|
||||
lsp::MessageType::WARNING => PromptLevel::Warning,
|
||||
_ => PromptLevel::Info,
|
||||
},
|
||||
message: params.message,
|
||||
actions,
|
||||
response_channel: tx,
|
||||
lsp_name: name.clone(),
|
||||
let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
|
||||
let level = match params.typ {
|
||||
lsp::MessageType::ERROR => PromptLevel::Critical,
|
||||
lsp::MessageType::WARNING => PromptLevel::Warning,
|
||||
_ => PromptLevel::Info,
|
||||
};
|
||||
let request = LanguageServerPromptRequest::new(
|
||||
level,
|
||||
params.message,
|
||||
actions,
|
||||
name.clone(),
|
||||
tx,
|
||||
);
|
||||
|
||||
let did_update = this
|
||||
.update(&mut cx, |_, cx| {
|
||||
|
|
@ -1141,17 +1143,13 @@ impl LocalLspStore {
|
|||
let mut cx = cx.clone();
|
||||
|
||||
let (tx, _) = smol::channel::bounded(1);
|
||||
let request = LanguageServerPromptRequest {
|
||||
level: match params.typ {
|
||||
lsp::MessageType::ERROR => PromptLevel::Critical,
|
||||
lsp::MessageType::WARNING => PromptLevel::Warning,
|
||||
_ => PromptLevel::Info,
|
||||
},
|
||||
message: params.message,
|
||||
actions: vec![],
|
||||
response_channel: tx,
|
||||
lsp_name: name,
|
||||
let level = match params.typ {
|
||||
lsp::MessageType::ERROR => PromptLevel::Critical,
|
||||
lsp::MessageType::WARNING => PromptLevel::Warning,
|
||||
_ => PromptLevel::Info,
|
||||
};
|
||||
let request =
|
||||
LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
|
||||
|
||||
let _ = this.update(&mut cx, |_, cx| {
|
||||
cx.emit(LspStoreEvent::LanguageServerPrompt(request));
|
||||
|
|
@ -13755,6 +13753,7 @@ struct LspBufferSnapshot {
|
|||
/// A prompt requested by LSP server.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LanguageServerPromptRequest {
|
||||
pub id: usize,
|
||||
pub level: PromptLevel,
|
||||
pub message: String,
|
||||
pub actions: Vec<MessageActionItem>,
|
||||
|
|
@ -13763,6 +13762,23 @@ pub struct LanguageServerPromptRequest {
|
|||
}
|
||||
|
||||
impl LanguageServerPromptRequest {
|
||||
pub fn new(
|
||||
level: PromptLevel,
|
||||
message: String,
|
||||
actions: Vec<MessageActionItem>,
|
||||
lsp_name: String,
|
||||
response_channel: smol::channel::Sender<MessageActionItem>,
|
||||
) -> Self {
|
||||
let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
|
||||
LanguageServerPromptRequest {
|
||||
id,
|
||||
level,
|
||||
message,
|
||||
actions,
|
||||
lsp_name,
|
||||
response_channel,
|
||||
}
|
||||
}
|
||||
pub async fn respond(self, index: usize) -> Option<()> {
|
||||
if let Some(response) = self.actions.into_iter().nth(index) {
|
||||
self.response_channel.send(response).await.ok()
|
||||
|
|
@ -13770,6 +13786,17 @@ impl LanguageServerPromptRequest {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn test(
|
||||
level: PromptLevel,
|
||||
message: String,
|
||||
actions: Vec<MessageActionItem>,
|
||||
lsp_name: String,
|
||||
) -> Self {
|
||||
let (tx, _rx) = smol::channel::unbounded();
|
||||
LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
|
||||
}
|
||||
}
|
||||
impl PartialEq for LanguageServerPromptRequest {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
|
|
|
|||
|
|
@ -4913,13 +4913,15 @@ impl Project {
|
|||
})
|
||||
.collect();
|
||||
this.update(&mut cx, |_, cx| {
|
||||
cx.emit(Event::LanguageServerPrompt(LanguageServerPromptRequest {
|
||||
level: proto_to_prompt(envelope.payload.level.context("Invalid prompt level")?),
|
||||
message: envelope.payload.message,
|
||||
actions: actions.clone(),
|
||||
lsp_name: envelope.payload.lsp_name,
|
||||
response_channel: tx,
|
||||
}));
|
||||
cx.emit(Event::LanguageServerPrompt(
|
||||
LanguageServerPromptRequest::new(
|
||||
proto_to_prompt(envelope.payload.level.context("Invalid prompt level")?),
|
||||
envelope.payload.message,
|
||||
actions.clone(),
|
||||
envelope.payload.lsp_name,
|
||||
tx,
|
||||
),
|
||||
));
|
||||
|
||||
anyhow::Ok(())
|
||||
})?;
|
||||
|
|
|
|||
|
|
@ -123,6 +123,17 @@ pub struct GlobalLspSettings {
|
|||
///
|
||||
/// Default: `true`
|
||||
pub button: bool,
|
||||
pub notifications: LspNotificationSettings,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
|
||||
#[serde(tag = "source", rename_all = "snake_case")]
|
||||
pub struct LspNotificationSettings {
|
||||
/// Timeout in milliseconds for automatically dismissing language server notifications.
|
||||
/// Set to 0 to disable auto-dismiss.
|
||||
///
|
||||
/// Default: 5000
|
||||
pub dismiss_timeout_ms: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
|
||||
|
|
@ -614,6 +625,16 @@ impl Settings for ProjectSettings {
|
|||
.unwrap()
|
||||
.button
|
||||
.unwrap(),
|
||||
notifications: LspNotificationSettings {
|
||||
dismiss_timeout_ms: content
|
||||
.global_lsp_settings
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.notifications
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.dismiss_timeout_ms,
|
||||
},
|
||||
},
|
||||
dap: project
|
||||
.dap
|
||||
|
|
|
|||
|
|
@ -199,6 +199,18 @@ pub struct GlobalLspSettingsContent {
|
|||
///
|
||||
/// Default: `true`
|
||||
pub button: Option<bool>,
|
||||
/// Settings for language server notifications
|
||||
pub notifications: Option<LspNotificationSettingsContent>,
|
||||
}
|
||||
|
||||
#[with_fallible_options]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
|
||||
pub struct LspNotificationSettingsContent {
|
||||
/// Timeout in milliseconds for automatically dismissing language server notifications.
|
||||
/// Set to 0 to disable auto-dismiss.
|
||||
///
|
||||
/// Default: 5000
|
||||
pub dismiss_timeout_ms: Option<u64>,
|
||||
}
|
||||
|
||||
#[with_fallible_options]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use crate::{SuppressNotification, Toast, Workspace};
|
||||
use anyhow::Context as _;
|
||||
use gpui::{
|
||||
AnyView, App, AppContext as _, AsyncWindowContext, ClickEvent, Context, DismissEvent, Entity,
|
||||
EventEmitter, FocusHandle, Focusable, PromptLevel, Render, ScrollHandle, Task,
|
||||
TextStyleRefinement, UnderlineStyle, svg,
|
||||
AnyEntity, AnyView, App, AppContext as _, AsyncWindowContext, ClickEvent, Context,
|
||||
DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, PromptLevel, Render, ScrollHandle,
|
||||
Task, TextStyleRefinement, UnderlineStyle, svg,
|
||||
};
|
||||
use markdown::{Markdown, MarkdownElement, MarkdownStyle};
|
||||
use parking_lot::Mutex;
|
||||
use project::project_settings::ProjectSettings;
|
||||
use settings::Settings;
|
||||
use theme::ThemeSettings;
|
||||
|
||||
|
|
@ -99,6 +100,40 @@ impl Workspace {
|
|||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
if let Ok(prompt) =
|
||||
AnyEntity::from(notification.clone()).downcast::<LanguageServerPrompt>()
|
||||
{
|
||||
let is_prompt_without_actions = prompt
|
||||
.read(cx)
|
||||
.request
|
||||
.as_ref()
|
||||
.is_some_and(|request| request.actions.is_empty());
|
||||
|
||||
let dismiss_timeout_ms = ProjectSettings::get_global(cx)
|
||||
.global_lsp_settings
|
||||
.notifications
|
||||
.dismiss_timeout_ms;
|
||||
|
||||
if is_prompt_without_actions {
|
||||
if let Some(dismiss_duration_ms) = dismiss_timeout_ms.filter(|&ms| ms > 0) {
|
||||
let task = cx.spawn({
|
||||
let id = id.clone();
|
||||
async move |this, cx| {
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(dismiss_duration_ms))
|
||||
.await;
|
||||
let _ = this.update(cx, |workspace, cx| {
|
||||
workspace.dismiss_notification(&id, cx);
|
||||
});
|
||||
}
|
||||
});
|
||||
prompt.update(cx, |prompt, _| {
|
||||
prompt.dismiss_task = Some(task);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
notification.into()
|
||||
});
|
||||
}
|
||||
|
|
@ -220,6 +255,7 @@ pub struct LanguageServerPrompt {
|
|||
request: Option<project::LanguageServerPromptRequest>,
|
||||
scroll_handle: ScrollHandle,
|
||||
markdown: Entity<Markdown>,
|
||||
dismiss_task: Option<Task<()>>,
|
||||
}
|
||||
|
||||
impl Focusable for LanguageServerPrompt {
|
||||
|
|
@ -239,6 +275,7 @@ impl LanguageServerPrompt {
|
|||
request: Some(request),
|
||||
scroll_handle: ScrollHandle::new(),
|
||||
markdown,
|
||||
dismiss_task: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -253,13 +290,20 @@ impl LanguageServerPrompt {
|
|||
.await
|
||||
.context("Stream already closed")?;
|
||||
|
||||
this.update(cx, |_, cx| cx.emit(DismissEvent));
|
||||
this.update(cx, |this, cx| {
|
||||
this.dismiss_notification(cx);
|
||||
});
|
||||
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.await
|
||||
.log_err();
|
||||
}
|
||||
|
||||
fn dismiss_notification(&mut self, cx: &mut Context<Self>) {
|
||||
self.dismiss_task = None;
|
||||
cx.emit(DismissEvent);
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for LanguageServerPrompt {
|
||||
|
|
@ -334,11 +378,11 @@ impl Render for LanguageServerPrompt {
|
|||
}
|
||||
})
|
||||
.on_click(cx.listener(
|
||||
move |_, _: &ClickEvent, _, cx| {
|
||||
move |this, _: &ClickEvent, _, cx| {
|
||||
if suppress {
|
||||
cx.emit(SuppressEvent);
|
||||
} else {
|
||||
cx.emit(DismissEvent);
|
||||
this.dismiss_notification(cx);
|
||||
}
|
||||
},
|
||||
)),
|
||||
|
|
@ -1161,3 +1205,211 @@ where
|
|||
self.prompt_err(msg, window, cx, f).detach();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fs::FakeFs;
|
||||
use gpui::TestAppContext;
|
||||
use project::{LanguageServerPromptRequest, Project};
|
||||
|
||||
use crate::tests::init_test;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_notification_auto_dismiss_with_notifications_from_multiple_language_servers(
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
let project = Project::test(fs, [], cx).await;
|
||||
|
||||
let (workspace, cx) =
|
||||
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
|
||||
|
||||
let count_notifications = |workspace: &Entity<Workspace>, cx: &mut TestAppContext| {
|
||||
workspace.read_with(cx, |workspace, _| workspace.notification_ids().len())
|
||||
};
|
||||
|
||||
let show_notification = |workspace: &Entity<Workspace>,
|
||||
cx: &mut TestAppContext,
|
||||
lsp_name: &str| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
let request = LanguageServerPromptRequest::test(
|
||||
gpui::PromptLevel::Warning,
|
||||
"Test notification".to_string(),
|
||||
vec![], // Empty actions triggers auto-dismiss
|
||||
lsp_name.to_string(),
|
||||
);
|
||||
let notification_id = NotificationId::composite::<LanguageServerPrompt>(request.id);
|
||||
workspace.show_notification(notification_id, cx, |cx| {
|
||||
cx.new(|cx| LanguageServerPrompt::new(request, cx))
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
show_notification(&workspace, cx, "Lsp1");
|
||||
assert_eq!(count_notifications(&workspace, cx), 1);
|
||||
|
||||
cx.executor().advance_clock(Duration::from_millis(1000));
|
||||
|
||||
show_notification(&workspace, cx, "Lsp2");
|
||||
assert_eq!(count_notifications(&workspace, cx), 2);
|
||||
|
||||
cx.executor().advance_clock(Duration::from_millis(1000));
|
||||
|
||||
show_notification(&workspace, cx, "Lsp3");
|
||||
assert_eq!(count_notifications(&workspace, cx), 3);
|
||||
|
||||
cx.executor().advance_clock(Duration::from_millis(3000));
|
||||
assert_eq!(count_notifications(&workspace, cx), 2);
|
||||
|
||||
cx.executor().advance_clock(Duration::from_millis(1000));
|
||||
assert_eq!(count_notifications(&workspace, cx), 1);
|
||||
|
||||
cx.executor().advance_clock(Duration::from_millis(1000));
|
||||
assert_eq!(count_notifications(&workspace, cx), 0);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_notification_auto_dismiss_with_multiple_notifications_from_single_language_server(
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
|
||||
let lsp_name = "server1";
|
||||
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
let project = Project::test(fs, [], cx).await;
|
||||
let (workspace, cx) =
|
||||
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
|
||||
|
||||
let count_notifications = |workspace: &Entity<Workspace>, cx: &mut TestAppContext| {
|
||||
workspace.read_with(cx, |workspace, _| workspace.notification_ids().len())
|
||||
};
|
||||
|
||||
let show_notification = |lsp_name: &str,
|
||||
workspace: &Entity<Workspace>,
|
||||
cx: &mut TestAppContext| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
let lsp_name = lsp_name.to_string();
|
||||
let request = LanguageServerPromptRequest::test(
|
||||
gpui::PromptLevel::Warning,
|
||||
"Test notification".to_string(),
|
||||
vec![], // Empty actions triggers auto-dismiss
|
||||
lsp_name,
|
||||
);
|
||||
let notification_id = NotificationId::composite::<LanguageServerPrompt>(request.id);
|
||||
|
||||
workspace.show_notification(notification_id, cx, |cx| {
|
||||
cx.new(|cx| LanguageServerPrompt::new(request, cx))
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
show_notification(lsp_name, &workspace, cx);
|
||||
assert_eq!(count_notifications(&workspace, cx), 1);
|
||||
|
||||
cx.executor().advance_clock(Duration::from_millis(1000));
|
||||
|
||||
show_notification(lsp_name, &workspace, cx);
|
||||
assert_eq!(count_notifications(&workspace, cx), 2);
|
||||
|
||||
cx.executor().advance_clock(Duration::from_millis(4000));
|
||||
assert_eq!(count_notifications(&workspace, cx), 1);
|
||||
|
||||
cx.executor().advance_clock(Duration::from_millis(1000));
|
||||
assert_eq!(count_notifications(&workspace, cx), 0);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_notification_auto_dismiss_turned_off(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
cx.update(|cx| {
|
||||
let mut settings = ProjectSettings::get_global(cx).clone();
|
||||
settings
|
||||
.global_lsp_settings
|
||||
.notifications
|
||||
.dismiss_timeout_ms = Some(0);
|
||||
ProjectSettings::override_global(settings, cx);
|
||||
});
|
||||
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
let project = Project::test(fs, [], cx).await;
|
||||
let (workspace, cx) =
|
||||
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
|
||||
|
||||
let count_notifications = |workspace: &Entity<Workspace>, cx: &mut TestAppContext| {
|
||||
workspace.read_with(cx, |workspace, _| workspace.notification_ids().len())
|
||||
};
|
||||
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
let request = LanguageServerPromptRequest::test(
|
||||
gpui::PromptLevel::Warning,
|
||||
"Test notification".to_string(),
|
||||
vec![], // Empty actions would trigger auto-dismiss if enabled
|
||||
"test_server".to_string(),
|
||||
);
|
||||
let notification_id = NotificationId::composite::<LanguageServerPrompt>(request.id);
|
||||
workspace.show_notification(notification_id, cx, |cx| {
|
||||
cx.new(|cx| LanguageServerPrompt::new(request, cx))
|
||||
});
|
||||
});
|
||||
|
||||
assert_eq!(count_notifications(&workspace, cx), 1);
|
||||
|
||||
// Advance time beyond the default auto-dismiss duration
|
||||
cx.executor().advance_clock(Duration::from_millis(10000));
|
||||
assert_eq!(count_notifications(&workspace, cx), 1);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_notification_auto_dismiss_with_custom_duration(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let custom_duration_ms: u64 = 2000;
|
||||
cx.update(|cx| {
|
||||
let mut settings = ProjectSettings::get_global(cx).clone();
|
||||
settings
|
||||
.global_lsp_settings
|
||||
.notifications
|
||||
.dismiss_timeout_ms = Some(custom_duration_ms);
|
||||
ProjectSettings::override_global(settings, cx);
|
||||
});
|
||||
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
let project = Project::test(fs, [], cx).await;
|
||||
let (workspace, cx) =
|
||||
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
|
||||
|
||||
let count_notifications = |workspace: &Entity<Workspace>, cx: &mut TestAppContext| {
|
||||
workspace.read_with(cx, |workspace, _| workspace.notification_ids().len())
|
||||
};
|
||||
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
let request = LanguageServerPromptRequest::test(
|
||||
gpui::PromptLevel::Warning,
|
||||
"Test notification".to_string(),
|
||||
vec![], // Empty actions triggers auto-dismiss
|
||||
"test_server".to_string(),
|
||||
);
|
||||
let notification_id = NotificationId::composite::<LanguageServerPrompt>(request.id);
|
||||
workspace.show_notification(notification_id, cx, |cx| {
|
||||
cx.new(|cx| LanguageServerPrompt::new(request, cx))
|
||||
});
|
||||
});
|
||||
|
||||
assert_eq!(count_notifications(&workspace, cx), 1);
|
||||
|
||||
// Advance time less than custom duration
|
||||
cx.executor()
|
||||
.advance_clock(Duration::from_millis(custom_duration_ms - 500));
|
||||
assert_eq!(count_notifications(&workspace, cx), 1);
|
||||
|
||||
// Advance time past the custom duration
|
||||
cx.executor().advance_clock(Duration::from_millis(1000));
|
||||
assert_eq!(count_notifications(&workspace, cx), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,9 +104,9 @@ use std::{
|
|||
borrow::Cow,
|
||||
cell::RefCell,
|
||||
cmp,
|
||||
collections::{VecDeque, hash_map::DefaultHasher},
|
||||
collections::VecDeque,
|
||||
env,
|
||||
hash::{Hash, Hasher},
|
||||
hash::Hash,
|
||||
path::{Path, PathBuf},
|
||||
process::ExitStatus,
|
||||
rc::Rc,
|
||||
|
|
@ -1359,12 +1359,8 @@ impl Workspace {
|
|||
project::Event::LanguageServerPrompt(request) => {
|
||||
struct LanguageServerPrompt;
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
request.lsp_name.as_str().hash(&mut hasher);
|
||||
let id = hasher.finish();
|
||||
|
||||
this.show_notification(
|
||||
NotificationId::composite::<LanguageServerPrompt>(id as usize),
|
||||
NotificationId::composite::<LanguageServerPrompt>(request.id),
|
||||
cx,
|
||||
|cx| {
|
||||
cx.new(|cx| {
|
||||
|
|
|
|||
|
|
@ -1598,7 +1598,12 @@ While other options may be changed at a runtime and should be placed under `sett
|
|||
```json [settings]
|
||||
{
|
||||
"global_lsp_settings": {
|
||||
"button": true
|
||||
"button": true,
|
||||
"notifications": {
|
||||
// Timeout in milliseconds for automatically dismissing language server notifications.
|
||||
// Set to 0 to disable auto-dismiss.
|
||||
"dismiss_timeout_ms": 5000
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -1606,6 +1611,8 @@ While other options may be changed at a runtime and should be placed under `sett
|
|||
**Options**
|
||||
|
||||
- `button`: Whether to show the LSP status button in the status bar
|
||||
- `notifications`: Notification-related settings.
|
||||
- `dismiss_timeout_ms`: Timeout in milliseconds for automatically dismissing language server notifications. Set to 0 to disable auto-dismiss.
|
||||
|
||||
## LSP Highlight Debounce
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue