Limit LSP non-invalidating queries

This commit is contained in:
Kirill Bulatov 2023-08-26 13:06:50 +03:00
parent 2b007930a9
commit e6fb909d89

View file

@ -19,6 +19,7 @@ use project::{InlayHint, ResolveState};
use collections::{hash_map, HashMap, HashSet};
use language::language_settings::InlayHintSettings;
use smol::lock::Semaphore;
use sum_tree::Bias;
use text::ToOffset;
use util::post_inc;
@ -29,6 +30,7 @@ pub struct InlayHintCache {
version: usize,
pub(super) enabled: bool,
update_tasks: HashMap<ExcerptId, TasksForRanges>,
lsp_request_limiter: Arc<Semaphore>,
}
#[derive(Debug)]
@ -258,6 +260,7 @@ impl InlayHintCache {
hints: HashMap::default(),
update_tasks: HashMap::default(),
version: 0,
lsp_request_limiter: Arc::new(Semaphore::new(MAX_CONCURRENT_LSP_REQUESTS)),
}
}
@ -629,6 +632,7 @@ fn spawn_new_update_tasks(
buffer_snapshot.clone(),
Arc::clone(&visible_hints),
cached_excerpt_hints,
Arc::clone(&editor.inlay_hint_cache.lsp_request_limiter),
cx,
)
};
@ -733,6 +737,7 @@ fn determine_query_ranges(
})
}
const MAX_CONCURRENT_LSP_REQUESTS: usize = 5;
const INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS: u64 = 400;
fn new_update_task(
@ -742,6 +747,7 @@ fn new_update_task(
buffer_snapshot: BufferSnapshot,
visible_hints: Arc<Vec<Inlay>>,
cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
lsp_request_limiter: Arc<Semaphore>,
cx: &mut ViewContext<'_, '_, Editor>,
) -> Task<()> {
cx.spawn(|editor, mut cx| async move {
@ -756,6 +762,7 @@ fn new_update_task(
query,
invalidate,
range,
Arc::clone(&lsp_request_limiter),
closure_cx.clone(),
)
};
@ -826,10 +833,41 @@ async fn fetch_and_update_hints(
query: ExcerptQuery,
invalidate: bool,
fetch_range: Range<language::Anchor>,
lsp_request_limiter: Arc<Semaphore>,
mut cx: gpui::AsyncAppContext,
) -> anyhow::Result<()> {
let (lsp_request_guard, got_throttled) = if query.invalidate.should_invalidate() {
(None, false)
} else {
match lsp_request_limiter.try_acquire() {
Some(guard) => (Some(guard), false),
None => (Some(lsp_request_limiter.acquire().await), true),
}
};
let inlay_hints_fetch_task = editor
.update(&mut cx, |editor, cx| {
if got_throttled {
if let Some((_, _, current_visible_range)) = editor
.excerpt_visible_offsets(None, cx)
.remove(&query.excerpt_id)
{
let visible_offset_length = current_visible_range.len();
let double_visible_range = current_visible_range
.start
.saturating_sub(visible_offset_length)
..current_visible_range
.end
.saturating_add(visible_offset_length)
.min(buffer_snapshot.len());
if !double_visible_range
.contains(&fetch_range.start.to_offset(&buffer_snapshot))
&& !double_visible_range
.contains(&fetch_range.end.to_offset(&buffer_snapshot))
{
return None;
}
}
}
editor
.buffer()
.read(cx)
@ -847,6 +885,8 @@ async fn fetch_and_update_hints(
Some(task) => task.await.context("inlay hint fetch task")?,
None => return Ok(()),
};
drop(lsp_request_guard);
let background_task_buffer_snapshot = buffer_snapshot.clone();
let backround_fetch_range = fetch_range.clone();
let new_update = cx