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 collections::{hash_map, HashMap, HashSet};
use language::language_settings::InlayHintSettings; use language::language_settings::InlayHintSettings;
use smol::lock::Semaphore;
use sum_tree::Bias; use sum_tree::Bias;
use text::ToOffset; use text::ToOffset;
use util::post_inc; use util::post_inc;
@ -29,6 +30,7 @@ pub struct InlayHintCache {
version: usize, version: usize,
pub(super) enabled: bool, pub(super) enabled: bool,
update_tasks: HashMap<ExcerptId, TasksForRanges>, update_tasks: HashMap<ExcerptId, TasksForRanges>,
lsp_request_limiter: Arc<Semaphore>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -258,6 +260,7 @@ impl InlayHintCache {
hints: HashMap::default(), hints: HashMap::default(),
update_tasks: HashMap::default(), update_tasks: HashMap::default(),
version: 0, 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(), buffer_snapshot.clone(),
Arc::clone(&visible_hints), Arc::clone(&visible_hints),
cached_excerpt_hints, cached_excerpt_hints,
Arc::clone(&editor.inlay_hint_cache.lsp_request_limiter),
cx, 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; const INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS: u64 = 400;
fn new_update_task( fn new_update_task(
@ -742,6 +747,7 @@ fn new_update_task(
buffer_snapshot: BufferSnapshot, buffer_snapshot: BufferSnapshot,
visible_hints: Arc<Vec<Inlay>>, visible_hints: Arc<Vec<Inlay>>,
cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>, cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
lsp_request_limiter: Arc<Semaphore>,
cx: &mut ViewContext<'_, '_, Editor>, cx: &mut ViewContext<'_, '_, Editor>,
) -> Task<()> { ) -> Task<()> {
cx.spawn(|editor, mut cx| async move { cx.spawn(|editor, mut cx| async move {
@ -756,6 +762,7 @@ fn new_update_task(
query, query,
invalidate, invalidate,
range, range,
Arc::clone(&lsp_request_limiter),
closure_cx.clone(), closure_cx.clone(),
) )
}; };
@ -826,10 +833,41 @@ async fn fetch_and_update_hints(
query: ExcerptQuery, query: ExcerptQuery,
invalidate: bool, invalidate: bool,
fetch_range: Range<language::Anchor>, fetch_range: Range<language::Anchor>,
lsp_request_limiter: Arc<Semaphore>,
mut cx: gpui::AsyncAppContext, mut cx: gpui::AsyncAppContext,
) -> anyhow::Result<()> { ) -> 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 let inlay_hints_fetch_task = editor
.update(&mut cx, |editor, cx| { .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 editor
.buffer() .buffer()
.read(cx) .read(cx)
@ -847,6 +885,8 @@ async fn fetch_and_update_hints(
Some(task) => task.await.context("inlay hint fetch task")?, Some(task) => task.await.context("inlay hint fetch task")?,
None => return Ok(()), None => return Ok(()),
}; };
drop(lsp_request_guard);
let background_task_buffer_snapshot = buffer_snapshot.clone(); let background_task_buffer_snapshot = buffer_snapshot.clone();
let backround_fetch_range = fetch_range.clone(); let backround_fetch_range = fetch_range.clone();
let new_update = cx let new_update = cx