Simulate disk-based diagnostics finishing 1s after saving buffer
Previously, we would simulate disk-based diagnostics finishing after saving a buffer. However, the language server may produce diagnostics right after emitting the event, causing the diagnostics status bar item to not reflect the latest state of the buffer. With this change, we will instead simulate disk-based diagnostics finishing after 1s after saving the buffer (only for language servers that don't have the concept of disk-based diagnostics, such as TypeScript). This ensures we always reflect the latest state and doesn't cause the UI to flicker as a result of the LSP sending us diagnostics after every input.
This commit is contained in:
parent
fbd23986e3
commit
baee6d0342
1 changed files with 54 additions and 25 deletions
|
@ -59,7 +59,7 @@ use std::{
|
||||||
atomic::{AtomicUsize, Ordering::SeqCst},
|
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
time::Instant,
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use terminal::{Terminal, TerminalBuilder};
|
use terminal::{Terminal, TerminalBuilder};
|
||||||
use util::{debug_panic, defer, post_inc, ResultExt, TryFutureExt as _};
|
use util::{debug_panic, defer, post_inc, ResultExt, TryFutureExt as _};
|
||||||
|
@ -185,6 +185,7 @@ pub enum LanguageServerState {
|
||||||
language: Arc<Language>,
|
language: Arc<Language>,
|
||||||
adapter: Arc<CachedLspAdapter>,
|
adapter: Arc<CachedLspAdapter>,
|
||||||
server: Arc<LanguageServer>,
|
server: Arc<LanguageServer>,
|
||||||
|
simulate_disk_based_diagnostics_completion: Option<Task<()>>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1716,19 +1717,39 @@ impl Project {
|
||||||
.log_err();
|
.log_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
// After saving a buffer, simulate disk-based diagnostics being finished for languages
|
let language_server_id = self.language_server_id_for_buffer(buffer.read(cx), cx)?;
|
||||||
// that don't support a disk-based progress token.
|
if let Some(LanguageServerState::Running {
|
||||||
let (lsp_adapter, language_server) =
|
adapter,
|
||||||
self.language_server_for_buffer(buffer.read(cx), cx)?;
|
simulate_disk_based_diagnostics_completion,
|
||||||
if lsp_adapter.disk_based_diagnostics_progress_token.is_none() {
|
..
|
||||||
let server_id = language_server.server_id();
|
}) = self.language_servers.get_mut(&language_server_id)
|
||||||
self.disk_based_diagnostics_finished(server_id, cx);
|
{
|
||||||
self.broadcast_language_server_update(
|
// After saving a buffer using a language server that doesn't provide
|
||||||
server_id,
|
// a disk-based progress token, kick off a timer that will reset every
|
||||||
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
|
// time the buffer is saved. If the timer eventually fires, simulate
|
||||||
proto::LspDiskBasedDiagnosticsUpdated {},
|
// disk-based diagnostics being finished so that other pieces of UI
|
||||||
),
|
// (e.g., project diagnostics view, diagnostic status bar) can update.
|
||||||
);
|
// We don't emit an event right away because the language server might take
|
||||||
|
// some time to publish diagnostics.
|
||||||
|
if adapter.disk_based_diagnostics_progress_token.is_none() {
|
||||||
|
const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
|
||||||
|
|
||||||
|
let task = cx.spawn_weak(|this, mut cx| async move {
|
||||||
|
cx.background().timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE).await;
|
||||||
|
if let Some(this) = this.upgrade(&cx) {
|
||||||
|
this.update(&mut cx, |this, cx | {
|
||||||
|
this.disk_based_diagnostics_finished(language_server_id, cx);
|
||||||
|
this.broadcast_language_server_update(
|
||||||
|
language_server_id,
|
||||||
|
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
|
||||||
|
proto::LspDiskBasedDiagnosticsUpdated {},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*simulate_disk_based_diagnostics_completion = Some(task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -1749,6 +1770,7 @@ impl Project {
|
||||||
adapter,
|
adapter,
|
||||||
language,
|
language,
|
||||||
server,
|
server,
|
||||||
|
..
|
||||||
}) = self.language_servers.get(id)
|
}) = self.language_servers.get(id)
|
||||||
{
|
{
|
||||||
return Some((adapter, language, server));
|
return Some((adapter, language, server));
|
||||||
|
@ -2035,6 +2057,7 @@ impl Project {
|
||||||
adapter: adapter.clone(),
|
adapter: adapter.clone(),
|
||||||
language,
|
language,
|
||||||
server: language_server.clone(),
|
server: language_server.clone(),
|
||||||
|
simulate_disk_based_diagnostics_completion: None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.language_server_statuses.insert(
|
this.language_server_statuses.insert(
|
||||||
|
@ -3105,6 +3128,7 @@ impl Project {
|
||||||
adapter,
|
adapter,
|
||||||
language,
|
language,
|
||||||
server,
|
server,
|
||||||
|
..
|
||||||
}) = self.language_servers.get(server_id)
|
}) = self.language_servers.get(server_id)
|
||||||
{
|
{
|
||||||
let adapter = adapter.clone();
|
let adapter = adapter.clone();
|
||||||
|
@ -6178,22 +6202,27 @@ impl Project {
|
||||||
buffer: &Buffer,
|
buffer: &Buffer,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> Option<(&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> {
|
) -> Option<(&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> {
|
||||||
|
let server_id = self.language_server_id_for_buffer(buffer, cx)?;
|
||||||
|
let server = self.language_servers.get(&server_id)?;
|
||||||
|
if let LanguageServerState::Running {
|
||||||
|
adapter, server, ..
|
||||||
|
} = server
|
||||||
|
{
|
||||||
|
Some((adapter, server))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn language_server_id_for_buffer(&self, buffer: &Buffer, cx: &AppContext) -> Option<usize> {
|
||||||
if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
|
if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
|
||||||
let name = language.lsp_adapter()?.name.clone();
|
let name = language.lsp_adapter()?.name.clone();
|
||||||
let worktree_id = file.worktree_id(cx);
|
let worktree_id = file.worktree_id(cx);
|
||||||
let key = (worktree_id, name);
|
let key = (worktree_id, name);
|
||||||
|
self.language_server_ids.get(&key).copied()
|
||||||
if let Some(server_id) = self.language_server_ids.get(&key) {
|
} else {
|
||||||
if let Some(LanguageServerState::Running {
|
None
|
||||||
adapter, server, ..
|
|
||||||
}) = self.language_servers.get(server_id)
|
|
||||||
{
|
|
||||||
return Some((adapter, server));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue