Map the new interface

# Conflicts:
#	crates/project/src/lsp_store.rs

# Conflicts:
#	crates/project/src/lsp_store.rs

# Conflicts:
#	crates/editor/src/editor.rs
#	crates/project/src/lsp_store.rs
This commit is contained in:
Kirill Bulatov 2025-07-17 13:11:23 +03:00
parent 64b14ef848
commit ee3245c9a5
6 changed files with 127 additions and 42 deletions

View file

@ -1611,7 +1611,7 @@ enum InlayHintRefreshReason {
SettingsChange(InlayHintSettings), SettingsChange(InlayHintSettings),
NewLinesShown, NewLinesShown,
BufferEdited(HashSet<Arc<Language>>), BufferEdited(HashSet<Arc<Language>>),
RefreshRequested, RefreshRequested(LanguageServerId),
ExcerptsRemoved(Vec<ExcerptId>), ExcerptsRemoved(Vec<ExcerptId>),
} }
@ -1623,7 +1623,7 @@ impl InlayHintRefreshReason {
Self::SettingsChange(_) => "settings change", Self::SettingsChange(_) => "settings change",
Self::NewLinesShown => "new lines shown", Self::NewLinesShown => "new lines shown",
Self::BufferEdited(_) => "buffer edited", Self::BufferEdited(_) => "buffer edited",
Self::RefreshRequested => "refresh requested", Self::RefreshRequested(_) => "refresh requested",
Self::ExcerptsRemoved(_) => "excerpts removed", Self::ExcerptsRemoved(_) => "excerpts removed",
} }
} }
@ -1864,8 +1864,11 @@ impl Editor {
project::Event::RefreshCodeLens => { project::Event::RefreshCodeLens => {
// we always query lens with actions, without storing them, always refreshing them // we always query lens with actions, without storing them, always refreshing them
} }
project::Event::RefreshInlayHints => { project::Event::RefreshInlayHints(server_id) => {
editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx); editor.refresh_inlay_hints(
InlayHintRefreshReason::RefreshRequested(*server_id),
cx,
);
} }
project::Event::LanguageServerAdded(..) project::Event::LanguageServerAdded(..)
| project::Event::LanguageServerRemoved(..) => { | project::Event::LanguageServerRemoved(..) => {
@ -5229,7 +5232,7 @@ impl Editor {
InlayHintRefreshReason::BufferEdited(buffer_languages) => { InlayHintRefreshReason::BufferEdited(buffer_languages) => {
(InvalidationStrategy::BufferEdited, Some(buffer_languages)) (InvalidationStrategy::BufferEdited, Some(buffer_languages))
} }
InlayHintRefreshReason::RefreshRequested => { InlayHintRefreshReason::RefreshRequested(_) => {
(InvalidationStrategy::RefreshRequested, None) (InvalidationStrategy::RefreshRequested, None)
} }
}; };
@ -16751,9 +16754,9 @@ impl Editor {
HashSet::default(), HashSet::default(),
cx, cx,
); );
cx.emit(project::Event::RefreshInlayHints);
}); });
}); });
self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
} }
} }

View file

@ -14,6 +14,9 @@ pub mod json_language_server_ext;
pub mod lsp_ext_command; pub mod lsp_ext_command;
pub mod rust_analyzer_ext; pub mod rust_analyzer_ext;
mod inlay_hint_cache;
use self::inlay_hint_cache::InlayHintCache;
use crate::{ use crate::{
CodeAction, ColorPresentation, Completion, CompletionResponse, CompletionSource, CodeAction, ColorPresentation, Completion, CompletionResponse, CompletionSource,
CoreCompletion, DocumentColor, Hover, InlayHint, LocationLink, LspAction, LspPullDiagnostics, CoreCompletion, DocumentColor, Hover, InlayHint, LocationLink, LspAction, LspPullDiagnostics,
@ -564,7 +567,7 @@ impl LocalLspStore {
} }
fn setup_lsp_messages( fn setup_lsp_messages(
this: WeakEntity<LspStore>, lsp_store: WeakEntity<LspStore>,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
language_server: &LanguageServer, language_server: &LanguageServer,
delegate: Arc<dyn LspAdapterDelegate>, delegate: Arc<dyn LspAdapterDelegate>,
@ -575,7 +578,7 @@ impl LocalLspStore {
language_server language_server
.on_notification::<lsp::notification::PublishDiagnostics, _>({ .on_notification::<lsp::notification::PublishDiagnostics, _>({
let adapter = adapter.clone(); let adapter = adapter.clone();
let this = this.clone(); let this = lsp_store.clone();
move |mut params, cx| { move |mut params, cx| {
let adapter = adapter.clone(); let adapter = adapter.clone();
if let Some(this) = this.upgrade() { if let Some(this) = this.upgrade() {
@ -619,7 +622,7 @@ impl LocalLspStore {
.on_request::<lsp::request::WorkspaceConfiguration, _, _>({ .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
let adapter = adapter.adapter.clone(); let adapter = adapter.adapter.clone();
let delegate = delegate.clone(); let delegate = delegate.clone();
let this = this.clone(); let this = lsp_store.clone();
let fs = fs.clone(); let fs = fs.clone();
move |params, cx| { move |params, cx| {
let adapter = adapter.clone(); let adapter = adapter.clone();
@ -667,7 +670,7 @@ impl LocalLspStore {
language_server language_server
.on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({ .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
let this = this.clone(); let this = lsp_store.clone();
move |_, cx| { move |_, cx| {
let this = this.clone(); let this = this.clone();
let cx = cx.clone(); let cx = cx.clone();
@ -695,7 +698,7 @@ impl LocalLspStore {
// to these requests when initializing. // to these requests when initializing.
language_server language_server
.on_request::<lsp::request::WorkDoneProgressCreate, _, _>({ .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
let this = this.clone(); let this = lsp_store.clone();
move |params, cx| { move |params, cx| {
let this = this.clone(); let this = this.clone();
let mut cx = cx.clone(); let mut cx = cx.clone();
@ -716,7 +719,7 @@ impl LocalLspStore {
language_server language_server
.on_request::<lsp::request::RegisterCapability, _, _>({ .on_request::<lsp::request::RegisterCapability, _, _>({
let lsp_store = this.clone(); let lsp_store = lsp_store.clone();
move |params, cx| { move |params, cx| {
let lsp_store = lsp_store.clone(); let lsp_store = lsp_store.clone();
let mut cx = cx.clone(); let mut cx = cx.clone();
@ -745,7 +748,7 @@ impl LocalLspStore {
language_server language_server
.on_request::<lsp::request::UnregisterCapability, _, _>({ .on_request::<lsp::request::UnregisterCapability, _, _>({
let lsp_store = this.clone(); let lsp_store = lsp_store.clone();
move |params, cx| { move |params, cx| {
let lsp_store = lsp_store.clone(); let lsp_store = lsp_store.clone();
let mut cx = cx.clone(); let mut cx = cx.clone();
@ -774,7 +777,7 @@ impl LocalLspStore {
language_server language_server
.on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({ .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
let this = this.clone(); let this = lsp_store.clone();
move |params, cx| { move |params, cx| {
let mut cx = cx.clone(); let mut cx = cx.clone();
let this = this.clone(); let this = this.clone();
@ -793,18 +796,22 @@ impl LocalLspStore {
language_server language_server
.on_request::<lsp::request::InlayHintRefreshRequest, _, _>({ .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
let this = this.clone(); let lsp_store = lsp_store.clone();
move |(), cx| { move |(), cx| {
let this = this.clone(); let this = lsp_store.clone();
let mut cx = cx.clone(); let mut cx = cx.clone();
async move { async move {
this.update(&mut cx, |this, cx| { this.update(&mut cx, |lsp_store, cx| {
cx.emit(LspStoreEvent::RefreshInlayHints); cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
this.downstream_client.as_ref().map(|(client, project_id)| { lsp_store
client.send(proto::RefreshInlayHints { .downstream_client
project_id: *project_id, .as_ref()
.map(|(client, project_id)| {
client.send(proto::RefreshInlayHints {
project_id: *project_id,
server_id: server_id.to_proto(),
})
}) })
})
})? })?
.transpose()?; .transpose()?;
Ok(()) Ok(())
@ -815,7 +822,7 @@ impl LocalLspStore {
language_server language_server
.on_request::<lsp::request::CodeLensRefresh, _, _>({ .on_request::<lsp::request::CodeLensRefresh, _, _>({
let this = this.clone(); let this = lsp_store.clone();
move |(), cx| { move |(), cx| {
let this = this.clone(); let this = this.clone();
let mut cx = cx.clone(); let mut cx = cx.clone();
@ -837,7 +844,7 @@ impl LocalLspStore {
language_server language_server
.on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({ .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
let this = this.clone(); let this = lsp_store.clone();
move |(), cx| { move |(), cx| {
let this = this.clone(); let this = this.clone();
let mut cx = cx.clone(); let mut cx = cx.clone();
@ -863,7 +870,7 @@ impl LocalLspStore {
language_server language_server
.on_request::<lsp::request::ShowMessageRequest, _, _>({ .on_request::<lsp::request::ShowMessageRequest, _, _>({
let this = this.clone(); let this = lsp_store.clone();
let name = name.to_string(); let name = name.to_string();
move |params, cx| { move |params, cx| {
let this = this.clone(); let this = this.clone();
@ -901,7 +908,7 @@ impl LocalLspStore {
.detach(); .detach();
language_server language_server
.on_notification::<lsp::notification::ShowMessage, _>({ .on_notification::<lsp::notification::ShowMessage, _>({
let this = this.clone(); let this = lsp_store.clone();
let name = name.to_string(); let name = name.to_string();
move |params, cx| { move |params, cx| {
let this = this.clone(); let this = this.clone();
@ -933,7 +940,7 @@ impl LocalLspStore {
language_server language_server
.on_notification::<lsp::notification::Progress, _>({ .on_notification::<lsp::notification::Progress, _>({
let this = this.clone(); let this = lsp_store.clone();
move |params, cx| { move |params, cx| {
if let Some(this) = this.upgrade() { if let Some(this) = this.upgrade() {
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
@ -952,7 +959,7 @@ impl LocalLspStore {
language_server language_server
.on_notification::<lsp::notification::LogMessage, _>({ .on_notification::<lsp::notification::LogMessage, _>({
let this = this.clone(); let this = lsp_store.clone();
move |params, cx| { move |params, cx| {
if let Some(this) = this.upgrade() { if let Some(this) = this.upgrade() {
this.update(cx, |_, cx| { this.update(cx, |_, cx| {
@ -970,7 +977,7 @@ impl LocalLspStore {
language_server language_server
.on_notification::<lsp::notification::LogTrace, _>({ .on_notification::<lsp::notification::LogTrace, _>({
let this = this.clone(); let this = lsp_store.clone();
move |params, cx| { move |params, cx| {
let mut cx = cx.clone(); let mut cx = cx.clone();
if let Some(this) = this.upgrade() { if let Some(this) = this.upgrade() {
@ -988,8 +995,8 @@ impl LocalLspStore {
.detach(); .detach();
json_language_server_ext::register_requests(this.clone(), language_server); json_language_server_ext::register_requests(this.clone(), language_server);
rust_analyzer_ext::register_notifications(this.clone(), language_server); rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
clangd_ext::register_notifications(this, language_server, adapter); clangd_ext::register_notifications(lsp_store, language_server, adapter);
} }
fn shutdown_language_servers_on_quit( fn shutdown_language_servers_on_quit(
@ -3491,6 +3498,7 @@ pub struct LspStore {
pub(super) lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>, pub(super) lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
lsp_document_colors: HashMap<BufferId, DocumentColorData>, lsp_document_colors: HashMap<BufferId, DocumentColorData>,
lsp_code_lens: HashMap<BufferId, CodeLensData>, lsp_code_lens: HashMap<BufferId, CodeLensData>,
inlay_hint_data: HashMap<BufferId, InlayHintCache>,
running_lsp_requests: HashMap<TypeId, (Global, HashMap<LspRequestId, Task<()>>)>, running_lsp_requests: HashMap<TypeId, (Global, HashMap<LspRequestId, Task<()>>)>,
} }
@ -3540,7 +3548,7 @@ pub enum LspStoreEvent {
new_language: Option<Arc<Language>>, new_language: Option<Arc<Language>>,
}, },
Notification(String), Notification(String),
RefreshInlayHints, RefreshInlayHints(LanguageServerId),
RefreshCodeLens, RefreshCodeLens,
DiagnosticsUpdated { DiagnosticsUpdated {
server_id: LanguageServerId, server_id: LanguageServerId,
@ -3762,6 +3770,7 @@ impl LspStore {
lsp_server_capabilities: HashMap::default(), lsp_server_capabilities: HashMap::default(),
lsp_document_colors: HashMap::default(), lsp_document_colors: HashMap::default(),
lsp_code_lens: HashMap::default(), lsp_code_lens: HashMap::default(),
inlay_hint_data: HashMap::default(),
running_lsp_requests: HashMap::default(), running_lsp_requests: HashMap::default(),
active_entry: None, active_entry: None,
_maintain_workspace_config, _maintain_workspace_config,
@ -3824,6 +3833,7 @@ impl LspStore {
lsp_server_capabilities: HashMap::default(), lsp_server_capabilities: HashMap::default(),
lsp_document_colors: HashMap::default(), lsp_document_colors: HashMap::default(),
lsp_code_lens: HashMap::default(), lsp_code_lens: HashMap::default(),
inlay_hint_data: HashMap::default(),
running_lsp_requests: HashMap::default(), running_lsp_requests: HashMap::default(),
active_entry: None, active_entry: None,
@ -4125,6 +4135,7 @@ impl LspStore {
if refcount == 0 { if refcount == 0 {
lsp_store.lsp_document_colors.remove(&buffer_id); lsp_store.lsp_document_colors.remove(&buffer_id);
lsp_store.lsp_code_lens.remove(&buffer_id); lsp_store.lsp_code_lens.remove(&buffer_id);
lsp_store.inlay_hint_data.remove(&buffer_id);
let local = lsp_store.as_local_mut().unwrap(); let local = lsp_store.as_local_mut().unwrap();
local.registered_buffers.remove(&buffer_id); local.registered_buffers.remove(&buffer_id);
local.buffers_opened_in_servers.remove(&buffer_id); local.buffers_opened_in_servers.remove(&buffer_id);
@ -9524,7 +9535,7 @@ impl LspStore {
if let Some(work) = status.pending_work.remove(&token) if let Some(work) = status.pending_work.remove(&token)
&& !work.is_disk_based_diagnostics_progress && !work.is_disk_based_diagnostics_progress
{ {
cx.emit(LspStoreEvent::RefreshInlayHints); cx.emit(LspStoreEvent::RefreshInlayHints(language_server_id));
} }
cx.notify(); cx.notify();
} }
@ -9656,12 +9667,14 @@ impl LspStore {
} }
async fn handle_refresh_inlay_hints( async fn handle_refresh_inlay_hints(
this: Entity<Self>, lsp_store: Entity<Self>,
_: TypedEnvelope<proto::RefreshInlayHints>, envelope: TypedEnvelope<proto::RefreshInlayHints>,
mut cx: AsyncApp, mut cx: AsyncApp,
) -> Result<proto::Ack> { ) -> Result<proto::Ack> {
this.update(&mut cx, |_, cx| { lsp_store.update(&mut cx, |_, cx| {
cx.emit(LspStoreEvent::RefreshInlayHints); cx.emit(LspStoreEvent::RefreshInlayHints(
LanguageServerId::from_proto(envelope.payload.server_id),
));
})?; })?;
Ok(proto::Ack {}) Ok(proto::Ack {})
} }
@ -10913,7 +10926,7 @@ impl LspStore {
language_server.name(), language_server.name(),
Some(key.worktree_id), Some(key.worktree_id),
)); ));
cx.emit(LspStoreEvent::RefreshInlayHints); cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
let server_capabilities = language_server.capabilities(); let server_capabilities = language_server.capabilities();
if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() { if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
@ -11517,6 +11530,10 @@ impl LspStore {
buffer_servers.remove(&for_server); buffer_servers.remove(&for_server);
} }
} }
for inlay_hint_cache in self.inlay_hint_data.values_mut() {
inlay_hint_cache.remove_server_data(for_server);
}
} }
pub fn result_id( pub fn result_id(

View file

@ -0,0 +1,56 @@
use std::{collections::BTreeMap, ops::Range};
use clock::Global;
use collections::HashMap;
use futures::future::Shared;
use gpui::{Context, Entity, Task};
use language::BufferRow;
use lsp::LanguageServerId;
use text::BufferId;
use crate::{InlayHint, buffer_store::BufferStore};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InlayHintId(usize);
#[derive(Debug)]
pub struct InlayHintCache {
buffer_store: Entity<BufferStore>,
hints_for_version: Global,
hints: HashMap<LanguageServerId, Hints>,
cache_version: usize,
}
#[derive(Debug, Default)]
struct Hints {
hints: HashMap<InlayHintId, InlayHint>,
hints_by_chunks: BTreeMap<Range<BufferRow>, Option<Vec<InlayHintId>>>,
hint_updates: HashMap<Range<BufferRow>, Shared<Task<InlayHints>>>,
}
pub struct InlayHints {
pub cache_version: usize,
pub hints: Vec<InlayHint>,
}
impl InlayHintCache {
pub fn remove_server_data(&mut self, for_server: LanguageServerId) -> bool {
let removed = self.hints.remove(&for_server).is_some();
if removed {
self.cache_version += 1;
}
removed
}
pub fn hints(
&self,
buffer: BufferId,
range: Range<usize>,
known_cache_version: Option<usize>,
cx: &mut Context<Self>,
) -> Option<Shared<Task<InlayHints>>> {
todo!("TODO kb")
}
// we want to store the cache version outbound, so they can query with it: we can return nothing (`Option`) if the version matches
// we can get a new server up/down, so we want to re-query for them things, ignoring the cache version
}

View file

@ -322,7 +322,7 @@ pub enum Event {
HostReshared, HostReshared,
Reshared, Reshared,
Rejoined, Rejoined,
RefreshInlayHints, RefreshInlayHints(LanguageServerId),
RefreshCodeLens, RefreshCodeLens,
RevealInProjectPanel(ProjectEntryId), RevealInProjectPanel(ProjectEntryId),
SnippetEdit(BufferId, Vec<(lsp::Range, Snippet)>), SnippetEdit(BufferId, Vec<(lsp::Range, Snippet)>),
@ -2922,7 +2922,9 @@ impl Project {
return; return;
}; };
} }
LspStoreEvent::RefreshInlayHints => cx.emit(Event::RefreshInlayHints), LspStoreEvent::RefreshInlayHints(server_id) => {
cx.emit(Event::RefreshInlayHints(*server_id))
}
LspStoreEvent::RefreshCodeLens => cx.emit(Event::RefreshCodeLens), LspStoreEvent::RefreshCodeLens => cx.emit(Event::RefreshCodeLens),
LspStoreEvent::LanguageServerPrompt(prompt) => { LspStoreEvent::LanguageServerPrompt(prompt) => {
cx.emit(Event::LanguageServerPrompt(prompt.clone())) cx.emit(Event::LanguageServerPrompt(prompt.clone()))

View file

@ -1804,7 +1804,10 @@ async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) {
fake_server fake_server
.start_progress(format!("{}/0", progress_token)) .start_progress(format!("{}/0", progress_token))
.await; .await;
assert_eq!(events.next().await.unwrap(), Event::RefreshInlayHints); assert_eq!(
events.next().await.unwrap(),
Event::RefreshInlayHints(fake_server.server.server_id())
);
assert_eq!( assert_eq!(
events.next().await.unwrap(), events.next().await.unwrap(),
Event::DiskBasedDiagnosticsStarted { Event::DiskBasedDiagnosticsStarted {
@ -1943,7 +1946,10 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC
Some(worktree_id) Some(worktree_id)
) )
); );
assert_eq!(events.next().await.unwrap(), Event::RefreshInlayHints); assert_eq!(
events.next().await.unwrap(),
Event::RefreshInlayHints(fake_server.server.server_id())
);
fake_server.start_progress(progress_token).await; fake_server.start_progress(progress_token).await;
assert_eq!( assert_eq!(
events.next().await.unwrap(), events.next().await.unwrap(),

View file

@ -465,6 +465,7 @@ message ResolveInlayHintResponse {
message RefreshInlayHints { message RefreshInlayHints {
uint64 project_id = 1; uint64 project_id = 1;
uint64 server_id = 2;
} }
message CodeLens { message CodeLens {