Allow using the inline assistant within the assistant panel (#11754)

Release Notes:

- Added the ability to use the inline assistant within the assistant
panel.
This commit is contained in:
Antonio Scandurra 2024-05-14 13:42:32 +02:00 committed by GitHub
parent 4766b41e96
commit e4c95b25bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -31,7 +31,7 @@ use gpui::{
StatefulInteractiveElement, Styled, Subscription, Task, TextStyle, UniformListScrollHandle, StatefulInteractiveElement, Styled, Subscription, Task, TextStyle, UniformListScrollHandle,
View, ViewContext, VisualContext, WeakModel, WeakView, WhiteSpace, WindowContext, View, ViewContext, VisualContext, WeakModel, WeakView, WhiteSpace, WindowContext,
}; };
use language::{language_settings::SoftWrap, Buffer, LanguageRegistry, ToOffset as _}; use language::{language_settings::SoftWrap, Buffer, LanguageRegistry, Point, ToOffset as _};
use multi_buffer::MultiBufferRow; use multi_buffer::MultiBufferRow;
use parking_lot::Mutex; use parking_lot::Mutex;
use project::Project; use project::Project;
@ -251,11 +251,31 @@ impl AssistantPanel {
let Some(assistant) = workspace.panel::<AssistantPanel>(cx) else { let Some(assistant) = workspace.panel::<AssistantPanel>(cx) else {
return; return;
}; };
let active_editor = if let Some(active_editor) = workspace
let conversation_editor =
assistant
.read(cx)
.active_conversation_editor()
.and_then(|editor| {
let editor = &editor.read(cx).editor;
if editor.read(cx).is_focused(cx) {
Some(editor.clone())
} else {
None
}
});
let show_include_conversation;
let active_editor;
if let Some(conversation_editor) = conversation_editor {
active_editor = conversation_editor;
show_include_conversation = false;
} else if let Some(workspace_editor) = workspace
.active_item(cx) .active_item(cx)
.and_then(|item| item.act_as::<Editor>(cx)) .and_then(|item| item.act_as::<Editor>(cx))
{ {
active_editor active_editor = workspace_editor;
show_include_conversation = true;
} else { } else {
return; return;
}; };
@ -263,7 +283,7 @@ impl AssistantPanel {
if assistant.update(cx, |assistant, cx| assistant.is_authenticated(cx)) { if assistant.update(cx, |assistant, cx| assistant.is_authenticated(cx)) {
assistant.update(cx, |assistant, cx| { assistant.update(cx, |assistant, cx| {
assistant.new_inline_assist(&active_editor, cx, &project) assistant.new_inline_assist(&active_editor, &project, show_include_conversation, cx)
}); });
} else { } else {
let assistant = assistant.downgrade(); let assistant = assistant.downgrade();
@ -273,7 +293,12 @@ impl AssistantPanel {
.await?; .await?;
if assistant.update(&mut cx, |assistant, cx| assistant.is_authenticated(cx))? { if assistant.update(&mut cx, |assistant, cx| assistant.is_authenticated(cx))? {
assistant.update(&mut cx, |assistant, cx| { assistant.update(&mut cx, |assistant, cx| {
assistant.new_inline_assist(&active_editor, cx, &project) assistant.new_inline_assist(
&active_editor,
&project,
show_include_conversation,
cx,
)
})?; })?;
} else { } else {
workspace.update(&mut cx, |workspace, cx| { workspace.update(&mut cx, |workspace, cx| {
@ -290,8 +315,9 @@ impl AssistantPanel {
fn new_inline_assist( fn new_inline_assist(
&mut self, &mut self,
editor: &View<Editor>, editor: &View<Editor>,
cx: &mut ViewContext<Self>,
project: &Model<Project>, project: &Model<Project>,
show_include_conversation: bool,
cx: &mut ViewContext<Self>,
) { ) {
let selection = editor.read(cx).selections.newest_anchor().clone(); let selection = editor.read(cx).selections.newest_anchor().clone();
if selection.start.excerpt_id != selection.end.excerpt_id { if selection.start.excerpt_id != selection.end.excerpt_id {
@ -331,7 +357,8 @@ impl AssistantPanel {
InlineAssistant::new( InlineAssistant::new(
inline_assist_id, inline_assist_id,
measurements.clone(), measurements.clone(),
self.include_conversation_in_next_inline_assist, show_include_conversation,
show_include_conversation && self.include_conversation_in_next_inline_assist,
self.inline_prompt_history.clone(), self.inline_prompt_history.clone(),
codegen.clone(), codegen.clone(),
self.workspace.clone(), self.workspace.clone(),
@ -345,7 +372,7 @@ impl AssistantPanel {
editor.insert_blocks( editor.insert_blocks(
[BlockProperties { [BlockProperties {
style: BlockStyle::Flex, style: BlockStyle::Flex,
position: snapshot.anchor_before(point_selection.head()), position: snapshot.anchor_before(Point::new(point_selection.head().row, 0)),
height: 2, height: 2,
render: Box::new({ render: Box::new({
let inline_assistant = inline_assistant.clone(); let inline_assistant = inline_assistant.clone();
@ -2577,16 +2604,6 @@ impl EventEmitter<ConversationEditorEvent> for ConversationEditor {}
impl Render for ConversationEditor { impl Render for ConversationEditor {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element {
//
// The ConversationEditor has two main segments
//
// 1. Messages Editor
// 2. Context
// - File Context (currently only the active file)
// - Project Diagnostics (Planned)
// - Deep Code Context (Planned, for query and other tools for the model)
//
div() div()
.key_context("ConversationEditor") .key_context("ConversationEditor")
.capture_action(cx.listener(ConversationEditor::cancel_last_assist)) .capture_action(cx.listener(ConversationEditor::cancel_last_assist))
@ -2660,6 +2677,7 @@ struct InlineAssistant {
prompt_editor: View<Editor>, prompt_editor: View<Editor>,
workspace: WeakView<Workspace>, workspace: WeakView<Workspace>,
confirmed: bool, confirmed: bool,
show_include_conversation: bool,
include_conversation: bool, include_conversation: bool,
measurements: Arc<Mutex<BlockMeasurements>>, measurements: Arc<Mutex<BlockMeasurements>>,
prompt_history: VecDeque<String>, prompt_history: VecDeque<String>,
@ -2688,7 +2706,7 @@ impl Render for InlineAssistant {
h_flex() h_flex()
.justify_center() .justify_center()
.w(measurements.gutter_width) .w(measurements.gutter_width)
.child( .children(self.show_include_conversation.then(|| {
IconButton::new("include_conversation", IconName::Ai) IconButton::new("include_conversation", IconName::Ai)
.on_click(cx.listener(|this, _, cx| { .on_click(cx.listener(|this, _, cx| {
this.toggle_include_conversation(&ToggleIncludeConversation, cx) this.toggle_include_conversation(&ToggleIncludeConversation, cx)
@ -2700,8 +2718,8 @@ impl Render for InlineAssistant {
&ToggleIncludeConversation, &ToggleIncludeConversation,
cx, cx,
) )
}), })
) }))
.children(if let Some(error) = self.codegen.read(cx).error() { .children(if let Some(error) = self.codegen.read(cx).error() {
let error_message = SharedString::from(error.to_string()); let error_message = SharedString::from(error.to_string());
Some( Some(
@ -2730,9 +2748,11 @@ impl FocusableView for InlineAssistant {
} }
impl InlineAssistant { impl InlineAssistant {
#[allow(clippy::too_many_arguments)]
fn new( fn new(
id: usize, id: usize,
measurements: Arc<Mutex<BlockMeasurements>>, measurements: Arc<Mutex<BlockMeasurements>>,
show_include_conversation: bool,
include_conversation: bool, include_conversation: bool,
prompt_history: VecDeque<String>, prompt_history: VecDeque<String>,
codegen: Model<Codegen>, codegen: Model<Codegen>,
@ -2760,6 +2780,7 @@ impl InlineAssistant {
prompt_editor, prompt_editor,
workspace, workspace,
confirmed: false, confirmed: false,
show_include_conversation,
include_conversation, include_conversation,
measurements, measurements,
prompt_history, prompt_history,