Introduce following for assistant panel (#14479)

Release Notes:

- Added support for following into the assistant panel.

---------

Co-authored-by: Max <max@zed.dev>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra
2024-07-15 11:36:27 +02:00
committed by GitHub
co-authored by Max Max Brunsfeld Nathan
parent 977a1b7a82
commit decdd3b6ac
13 changed files with 819 additions and 541 deletions
+1 -1
View File
@@ -271,7 +271,7 @@ pub fn init(cx: &mut AppContext) {
init_settings(cx);
workspace::register_project_item::<Editor>(cx);
workspace::register_followable_item::<Editor>(cx);
workspace::FollowableViewRegistry::register::<Editor>(cx);
workspace::register_deserializable_item::<Editor>(cx);
cx.observe_new_views(
|workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
-2
View File
@@ -8812,7 +8812,6 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
let follower_1 = cx
.update_window(*workspace.deref(), |_, cx| {
Editor::from_state_proto(
pane.clone(),
workspace.root_view(cx).unwrap(),
ViewId {
creator: Default::default(),
@@ -8904,7 +8903,6 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
let follower_2 = cx
.update_window(*workspace.deref(), |_, cx| {
Editor::from_state_proto(
pane.clone(),
workspace.root_view(cx).unwrap().clone(),
ViewId {
creator: Default::default(),
+53 -62
View File
@@ -19,7 +19,7 @@ use multi_buffer::AnchorRangeExt;
use project::{search::SearchQuery, FormatTrigger, Item as _, Project, ProjectPath};
use rpc::proto::{self, update_view, PeerId};
use settings::Settings;
use workspace::item::{ItemSettings, TabContentParams};
use workspace::item::{Dedup, ItemSettings, TabContentParams};
use std::{
any::TypeId,
@@ -34,7 +34,7 @@ use text::{BufferId, Selection};
use theme::{Theme, ThemeSettings};
use ui::{h_flex, prelude::*, Label};
use util::{paths::PathExt, ResultExt, TryFutureExt};
use workspace::item::{BreadcrumbText, FollowEvent, FollowableItemHandle};
use workspace::item::{BreadcrumbText, FollowEvent};
use workspace::{
item::{FollowableItem, Item, ItemEvent, ItemHandle, ProjectItem},
searchable::{Direction, SearchEvent, SearchableItem, SearchableItemHandle},
@@ -49,7 +49,6 @@ impl FollowableItem for Editor {
}
fn from_state_proto(
pane: View<workspace::Pane>,
workspace: View<Workspace>,
remote_id: ViewId,
state: &mut Option<proto::view::Variant>,
@@ -63,7 +62,6 @@ impl FollowableItem for Editor {
unreachable!()
};
let client = project.read(cx).client();
let replica_id = project.read(cx).replica_id();
let buffer_ids = state
.excerpts
@@ -77,72 +75,55 @@ impl FollowableItem for Editor {
.collect::<Result<Vec<_>>>()
});
let pane = pane.downgrade();
Some(cx.spawn(|mut cx| async move {
let mut buffers = futures::future::try_join_all(buffers?)
.await
.debug_assert_ok("leaders don't share views for unshared buffers")?;
let editor = pane.update(&mut cx, |pane, cx| {
let mut editors = pane.items_of_type::<Self>();
editors.find(|editor| {
let ids_match = editor.remote_id(&client, cx) == Some(remote_id);
let singleton_buffer_matches = state.singleton
&& buffers.first()
== editor.read(cx).buffer.read(cx).as_singleton().as_ref();
ids_match || singleton_buffer_matches
let editor = cx.update(|cx| {
let multibuffer = cx.new_model(|cx| {
let mut multibuffer;
if state.singleton && buffers.len() == 1 {
multibuffer = MultiBuffer::singleton(buffers.pop().unwrap(), cx)
} else {
multibuffer = MultiBuffer::new(replica_id, project.read(cx).capability());
let mut excerpts = state.excerpts.into_iter().peekable();
while let Some(excerpt) = excerpts.peek() {
let Ok(buffer_id) = BufferId::new(excerpt.buffer_id) else {
continue;
};
let buffer_excerpts = iter::from_fn(|| {
let excerpt = excerpts.peek()?;
(excerpt.buffer_id == u64::from(buffer_id))
.then(|| excerpts.next().unwrap())
});
let buffer =
buffers.iter().find(|b| b.read(cx).remote_id() == buffer_id);
if let Some(buffer) = buffer {
multibuffer.push_excerpts(
buffer.clone(),
buffer_excerpts.filter_map(deserialize_excerpt_range),
cx,
);
}
}
};
if let Some(title) = &state.title {
multibuffer = multibuffer.with_title(title.clone())
}
multibuffer
});
cx.new_view(|cx| {
let mut editor =
Editor::for_multibuffer(multibuffer, Some(project.clone()), true, cx);
editor.remote_id = Some(remote_id);
editor
})
})?;
let editor = if let Some(editor) = editor {
editor
} else {
pane.update(&mut cx, |_, cx| {
let multibuffer = cx.new_model(|cx| {
let mut multibuffer;
if state.singleton && buffers.len() == 1 {
multibuffer = MultiBuffer::singleton(buffers.pop().unwrap(), cx)
} else {
multibuffer =
MultiBuffer::new(replica_id, project.read(cx).capability());
let mut excerpts = state.excerpts.into_iter().peekable();
while let Some(excerpt) = excerpts.peek() {
let Ok(buffer_id) = BufferId::new(excerpt.buffer_id) else {
continue;
};
let buffer_excerpts = iter::from_fn(|| {
let excerpt = excerpts.peek()?;
(excerpt.buffer_id == u64::from(buffer_id))
.then(|| excerpts.next().unwrap())
});
let buffer =
buffers.iter().find(|b| b.read(cx).remote_id() == buffer_id);
if let Some(buffer) = buffer {
multibuffer.push_excerpts(
buffer.clone(),
buffer_excerpts.filter_map(deserialize_excerpt_range),
cx,
);
}
}
};
if let Some(title) = &state.title {
multibuffer = multibuffer.with_title(title.clone())
}
multibuffer
});
cx.new_view(|cx| {
let mut editor =
Editor::for_multibuffer(multibuffer, Some(project.clone()), true, cx);
editor.remote_id = Some(remote_id);
editor
})
})?
};
update_editor_from_message(
editor.downgrade(),
project,
@@ -327,6 +308,16 @@ impl FollowableItem for Editor {
fn is_project_item(&self, _cx: &WindowContext) -> bool {
true
}
fn dedup(&self, existing: &Self, cx: &WindowContext) -> Option<Dedup> {
let self_singleton = self.buffer.read(cx).as_singleton()?;
let other_singleton = existing.buffer.read(cx).as_singleton()?;
if self_singleton == other_singleton {
Some(Dedup::KeepExisting)
} else {
None
}
}
}
async fn update_editor_from_message(