Fix inconsistencies in "Transform" vs "Generate" tooltips for assistant v2 (#22160)
Also makes the inline assistant and inline terminal assistant share a bunch more code. Release Notes: - N/A --------- Co-authored-by: Agus <agus@zed.dev> Co-authored-by: Agus Zubiaga <hi@aguz.me>
This commit is contained in:
parent
6192c83f23
commit
4bfc107e3a
4 changed files with 230 additions and 220 deletions
|
@ -6,6 +6,7 @@ mod context_picker;
|
||||||
mod context_store;
|
mod context_store;
|
||||||
mod context_strip;
|
mod context_strip;
|
||||||
mod inline_assistant;
|
mod inline_assistant;
|
||||||
|
mod inline_prompt_editor;
|
||||||
mod message_editor;
|
mod message_editor;
|
||||||
mod prompts;
|
mod prompts;
|
||||||
mod streaming_diff;
|
mod streaming_diff;
|
||||||
|
|
|
@ -2,6 +2,9 @@ use crate::context::attach_context_to_message;
|
||||||
use crate::context_picker::ContextPicker;
|
use crate::context_picker::ContextPicker;
|
||||||
use crate::context_store::ContextStore;
|
use crate::context_store::ContextStore;
|
||||||
use crate::context_strip::ContextStrip;
|
use crate::context_strip::ContextStrip;
|
||||||
|
use crate::inline_prompt_editor::{
|
||||||
|
render_cancel_button, CodegenStatus, PromptEditorEvent, PromptMode,
|
||||||
|
};
|
||||||
use crate::thread_store::ThreadStore;
|
use crate::thread_store::ThreadStore;
|
||||||
use crate::{
|
use crate::{
|
||||||
assistant_settings::AssistantSettings,
|
assistant_settings::AssistantSettings,
|
||||||
|
@ -652,7 +655,7 @@ impl InlineAssistant {
|
||||||
PromptEditorEvent::StopRequested => {
|
PromptEditorEvent::StopRequested => {
|
||||||
self.stop_assist(assist_id, cx);
|
self.stop_assist(assist_id, cx);
|
||||||
}
|
}
|
||||||
PromptEditorEvent::ConfirmRequested => {
|
PromptEditorEvent::ConfirmRequested { execute: _ } => {
|
||||||
self.finish_assist(assist_id, false, cx);
|
self.finish_assist(assist_id, false, cx);
|
||||||
}
|
}
|
||||||
PromptEditorEvent::CancelRequested => {
|
PromptEditorEvent::CancelRequested => {
|
||||||
|
@ -661,6 +664,9 @@ impl InlineAssistant {
|
||||||
PromptEditorEvent::DismissRequested => {
|
PromptEditorEvent::DismissRequested => {
|
||||||
self.dismiss_assist(assist_id, cx);
|
self.dismiss_assist(assist_id, cx);
|
||||||
}
|
}
|
||||||
|
PromptEditorEvent::Resized { .. } => {
|
||||||
|
// This only matters for the terminal inline
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1475,14 +1481,6 @@ impl InlineAssistGroupId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PromptEditorEvent {
|
|
||||||
StartRequested,
|
|
||||||
StopRequested,
|
|
||||||
ConfirmRequested,
|
|
||||||
CancelRequested,
|
|
||||||
DismissRequested,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PromptEditor {
|
struct PromptEditor {
|
||||||
id: InlineAssistId,
|
id: InlineAssistId,
|
||||||
editor: View<Editor>,
|
editor: View<Editor>,
|
||||||
|
@ -1510,93 +1508,20 @@ impl Render for PromptEditor {
|
||||||
if codegen.alternative_count(cx) > 1 {
|
if codegen.alternative_count(cx) > 1 {
|
||||||
buttons.push(self.render_cycle_controls(cx));
|
buttons.push(self.render_cycle_controls(cx));
|
||||||
}
|
}
|
||||||
|
let prompt_mode = if codegen.is_insertion {
|
||||||
let status = codegen.status(cx);
|
PromptMode::Generate {
|
||||||
buttons.extend(match status {
|
supports_execute: false,
|
||||||
CodegenStatus::Idle => {
|
|
||||||
vec![
|
|
||||||
IconButton::new("cancel", IconName::Close)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| Tooltip::for_action("Cancel Assist", &menu::Cancel, cx))
|
|
||||||
.on_click(
|
|
||||||
cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)),
|
|
||||||
)
|
|
||||||
.into_any_element(),
|
|
||||||
IconButton::new("start", IconName::SparkleAlt)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| Tooltip::for_action("Transform", &menu::Confirm, cx))
|
|
||||||
.on_click(
|
|
||||||
cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StartRequested)),
|
|
||||||
)
|
|
||||||
.into_any_element(),
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
CodegenStatus::Pending => {
|
|
||||||
vec![
|
|
||||||
IconButton::new("cancel", IconName::Close)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| Tooltip::text("Cancel Assist", cx))
|
|
||||||
.on_click(
|
|
||||||
cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)),
|
|
||||||
)
|
|
||||||
.into_any_element(),
|
|
||||||
IconButton::new("stop", IconName::Stop)
|
|
||||||
.icon_color(Color::Error)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| {
|
|
||||||
Tooltip::with_meta(
|
|
||||||
"Interrupt Transformation",
|
|
||||||
Some(&menu::Cancel),
|
|
||||||
"Changes won't be discarded",
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StopRequested)))
|
|
||||||
.into_any_element(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
CodegenStatus::Error(_) | CodegenStatus::Done => {
|
|
||||||
vec![
|
|
||||||
IconButton::new("cancel", IconName::Close)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| Tooltip::for_action("Cancel Assist", &menu::Cancel, cx))
|
|
||||||
.on_click(
|
|
||||||
cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)),
|
|
||||||
)
|
|
||||||
.into_any_element(),
|
|
||||||
if self.edited_since_done || matches!(status, CodegenStatus::Error(_)) {
|
|
||||||
IconButton::new("restart", IconName::RotateCw)
|
|
||||||
.icon_color(Color::Info)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| {
|
|
||||||
Tooltip::with_meta(
|
|
||||||
"Restart Transformation",
|
|
||||||
Some(&menu::Confirm),
|
|
||||||
"Changes will be discarded",
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.on_click(cx.listener(|_, _, cx| {
|
|
||||||
cx.emit(PromptEditorEvent::StartRequested);
|
|
||||||
}))
|
|
||||||
.into_any_element()
|
|
||||||
} else {
|
} else {
|
||||||
IconButton::new("confirm", IconName::Check)
|
PromptMode::Transform
|
||||||
.icon_color(Color::Info)
|
};
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| Tooltip::for_action("Confirm Assist", &menu::Confirm, cx))
|
buttons.extend(render_cancel_button(
|
||||||
.on_click(cx.listener(|_, _, cx| {
|
codegen.status(cx).into(),
|
||||||
cx.emit(PromptEditorEvent::ConfirmRequested);
|
self.edited_since_done,
|
||||||
}))
|
prompt_mode,
|
||||||
.into_any_element()
|
cx,
|
||||||
},
|
));
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.border_y_1()
|
.border_y_1()
|
||||||
|
@ -1747,7 +1672,7 @@ impl PromptEditor {
|
||||||
// always show the cursor (even when it isn't focused) because
|
// always show the cursor (even when it isn't focused) because
|
||||||
// typing in one will make what you typed appear in all of them.
|
// typing in one will make what you typed appear in all of them.
|
||||||
editor.set_show_cursor_when_unfocused(true, cx);
|
editor.set_show_cursor_when_unfocused(true, cx);
|
||||||
editor.set_placeholder_text(Self::placeholder_text(codegen.read(cx)), cx);
|
editor.set_placeholder_text(Self::placeholder_text(codegen.read(cx), cx), cx);
|
||||||
editor
|
editor
|
||||||
});
|
});
|
||||||
let context_picker_menu_handle = PopoverMenuHandle::default();
|
let context_picker_menu_handle = PopoverMenuHandle::default();
|
||||||
|
@ -1815,7 +1740,7 @@ impl PromptEditor {
|
||||||
self.editor = cx.new_view(|cx| {
|
self.editor = cx.new_view(|cx| {
|
||||||
let mut editor = Editor::auto_height(Self::MAX_LINES as usize, cx);
|
let mut editor = Editor::auto_height(Self::MAX_LINES as usize, cx);
|
||||||
editor.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
|
editor.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
|
||||||
editor.set_placeholder_text(Self::placeholder_text(self.codegen.read(cx)), cx);
|
editor.set_placeholder_text(Self::placeholder_text(self.codegen.read(cx), cx), cx);
|
||||||
editor.set_placeholder_text("Add a prompt…", cx);
|
editor.set_placeholder_text("Add a prompt…", cx);
|
||||||
editor.set_text(prompt, cx);
|
editor.set_text(prompt, cx);
|
||||||
if focus {
|
if focus {
|
||||||
|
@ -1826,14 +1751,17 @@ impl PromptEditor {
|
||||||
self.subscribe_to_editor(cx);
|
self.subscribe_to_editor(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn placeholder_text(codegen: &Codegen) -> String {
|
fn placeholder_text(codegen: &Codegen, cx: &WindowContext) -> String {
|
||||||
let action = if codegen.is_insertion {
|
let action = if codegen.is_insertion {
|
||||||
"Generate"
|
"Generate"
|
||||||
} else {
|
} else {
|
||||||
"Transform"
|
"Transform"
|
||||||
};
|
};
|
||||||
|
let assistant_panel_keybinding = ui::text_for_action(&crate::ToggleFocus, cx)
|
||||||
|
.map(|keybinding| format!("{keybinding} to chat ― "))
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
format!("{action}… ↓↑ for history")
|
format!("{action}… ({assistant_panel_keybinding}↓↑ for history)")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prompt(&self, cx: &AppContext) -> String {
|
fn prompt(&self, cx: &AppContext) -> String {
|
||||||
|
@ -1950,7 +1878,7 @@ impl PromptEditor {
|
||||||
if self.edited_since_done {
|
if self.edited_since_done {
|
||||||
cx.emit(PromptEditorEvent::StartRequested);
|
cx.emit(PromptEditorEvent::StartRequested);
|
||||||
} else {
|
} else {
|
||||||
cx.emit(PromptEditorEvent::ConfirmRequested);
|
cx.emit(PromptEditorEvent::ConfirmRequested { execute: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CodegenStatus::Error(_) => {
|
CodegenStatus::Error(_) => {
|
||||||
|
@ -2566,13 +2494,6 @@ pub struct CodegenAlternative {
|
||||||
message_id: Option<String>,
|
message_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CodegenStatus {
|
|
||||||
Idle,
|
|
||||||
Pending,
|
|
||||||
Done,
|
|
||||||
Error(anyhow::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Diff {
|
struct Diff {
|
||||||
deleted_row_ranges: Vec<(Anchor, RangeInclusive<u32>)>,
|
deleted_row_ranges: Vec<(Anchor, RangeInclusive<u32>)>,
|
||||||
|
|
191
crates/assistant2/src/inline_prompt_editor.rs
Normal file
191
crates/assistant2/src/inline_prompt_editor.rs
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
use gpui::{AnyElement, EventEmitter};
|
||||||
|
use ui::{prelude::*, IconButtonShape, Tooltip};
|
||||||
|
|
||||||
|
pub enum CodegenStatus {
|
||||||
|
Idle,
|
||||||
|
Pending,
|
||||||
|
Done,
|
||||||
|
Error(anyhow::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is just CodegenStatus without the anyhow::Error, which causes a lifetime issue for rendering the Cancel button.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum CancelButtonState {
|
||||||
|
Idle,
|
||||||
|
Pending,
|
||||||
|
Done,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<CancelButtonState> for &CodegenStatus {
|
||||||
|
fn into(self) -> CancelButtonState {
|
||||||
|
match self {
|
||||||
|
CodegenStatus::Idle => CancelButtonState::Idle,
|
||||||
|
CodegenStatus::Pending => CancelButtonState::Pending,
|
||||||
|
CodegenStatus::Done => CancelButtonState::Done,
|
||||||
|
CodegenStatus::Error(_) => CancelButtonState::Error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum PromptMode {
|
||||||
|
Generate { supports_execute: bool },
|
||||||
|
Transform,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PromptMode {
|
||||||
|
fn start_label(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
PromptMode::Generate { .. } => "Generate",
|
||||||
|
PromptMode::Transform => "Transform",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn tooltip_interrupt(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
PromptMode::Generate { .. } => "Interrupt Generation",
|
||||||
|
PromptMode::Transform => "Interrupt Transform",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tooltip_restart(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
PromptMode::Generate { .. } => "Restart Generation",
|
||||||
|
PromptMode::Transform => "Restart Transform",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tooltip_accept(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
PromptMode::Generate { .. } => "Accept Generation",
|
||||||
|
PromptMode::Transform => "Accept Transform",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_cancel_button<T: EventEmitter<PromptEditorEvent>>(
|
||||||
|
cancel_button_state: CancelButtonState,
|
||||||
|
edited_since_done: bool,
|
||||||
|
mode: PromptMode,
|
||||||
|
cx: &mut ViewContext<T>,
|
||||||
|
) -> Vec<AnyElement> {
|
||||||
|
match cancel_button_state {
|
||||||
|
CancelButtonState::Idle => {
|
||||||
|
vec![
|
||||||
|
IconButton::new("cancel", IconName::Close)
|
||||||
|
.icon_color(Color::Muted)
|
||||||
|
.shape(IconButtonShape::Square)
|
||||||
|
.tooltip(|cx| Tooltip::for_action("Cancel Assist", &menu::Cancel, cx))
|
||||||
|
.on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)))
|
||||||
|
.into_any_element(),
|
||||||
|
Button::new("start", mode.start_label())
|
||||||
|
.icon(IconName::Return)
|
||||||
|
.icon_color(Color::Muted)
|
||||||
|
.on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StartRequested)))
|
||||||
|
.into_any_element(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
CancelButtonState::Pending => vec![
|
||||||
|
IconButton::new("cancel", IconName::Close)
|
||||||
|
.icon_color(Color::Muted)
|
||||||
|
.shape(IconButtonShape::Square)
|
||||||
|
.tooltip(|cx| Tooltip::text("Cancel Assist", cx))
|
||||||
|
.on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)))
|
||||||
|
.into_any_element(),
|
||||||
|
IconButton::new("stop", IconName::Stop)
|
||||||
|
.icon_color(Color::Error)
|
||||||
|
.shape(IconButtonShape::Square)
|
||||||
|
.tooltip(move |cx| {
|
||||||
|
Tooltip::with_meta(
|
||||||
|
mode.tooltip_interrupt(),
|
||||||
|
Some(&menu::Cancel),
|
||||||
|
"Changes won't be discarded",
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StopRequested)))
|
||||||
|
.into_any_element(),
|
||||||
|
],
|
||||||
|
CancelButtonState::Done | CancelButtonState::Error => {
|
||||||
|
let cancel = IconButton::new("cancel", IconName::Close)
|
||||||
|
.icon_color(Color::Muted)
|
||||||
|
.shape(IconButtonShape::Square)
|
||||||
|
.tooltip(|cx| Tooltip::for_action("Cancel Assist", &menu::Cancel, cx))
|
||||||
|
.on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)))
|
||||||
|
.into_any_element();
|
||||||
|
|
||||||
|
let has_error = matches!(cancel_button_state, CancelButtonState::Error);
|
||||||
|
if has_error || edited_since_done {
|
||||||
|
vec![
|
||||||
|
cancel,
|
||||||
|
IconButton::new("restart", IconName::RotateCw)
|
||||||
|
.icon_color(Color::Info)
|
||||||
|
.shape(IconButtonShape::Square)
|
||||||
|
.tooltip(move |cx| {
|
||||||
|
Tooltip::with_meta(
|
||||||
|
mode.tooltip_restart(),
|
||||||
|
Some(&menu::Confirm),
|
||||||
|
"Changes will be discarded",
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.on_click(cx.listener(|_, _, cx| {
|
||||||
|
cx.emit(PromptEditorEvent::StartRequested);
|
||||||
|
}))
|
||||||
|
.into_any_element(),
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
let mut buttons = vec![
|
||||||
|
cancel,
|
||||||
|
IconButton::new("accept", IconName::Check)
|
||||||
|
.icon_color(Color::Info)
|
||||||
|
.shape(IconButtonShape::Square)
|
||||||
|
.tooltip(move |cx| {
|
||||||
|
Tooltip::for_action(mode.tooltip_accept(), &menu::Confirm, cx)
|
||||||
|
})
|
||||||
|
.on_click(cx.listener(|_, _, cx| {
|
||||||
|
cx.emit(PromptEditorEvent::ConfirmRequested { execute: false });
|
||||||
|
}))
|
||||||
|
.into_any_element(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match mode {
|
||||||
|
PromptMode::Generate { supports_execute } => {
|
||||||
|
if supports_execute {
|
||||||
|
buttons.push(
|
||||||
|
IconButton::new("confirm", IconName::Play)
|
||||||
|
.icon_color(Color::Info)
|
||||||
|
.shape(IconButtonShape::Square)
|
||||||
|
.tooltip(|cx| {
|
||||||
|
Tooltip::for_action(
|
||||||
|
"Execute Generated Command",
|
||||||
|
&menu::SecondaryConfirm,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.on_click(cx.listener(|_, _, cx| {
|
||||||
|
cx.emit(PromptEditorEvent::ConfirmRequested {
|
||||||
|
execute: true,
|
||||||
|
});
|
||||||
|
}))
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PromptMode::Transform => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum PromptEditorEvent {
|
||||||
|
StartRequested,
|
||||||
|
StopRequested,
|
||||||
|
ConfirmRequested { execute: bool },
|
||||||
|
CancelRequested,
|
||||||
|
DismissRequested,
|
||||||
|
Resized { height_in_lines: u8 },
|
||||||
|
}
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::assistant_settings::AssistantSettings;
|
|
||||||
use crate::context::attach_context_to_message;
|
use crate::context::attach_context_to_message;
|
||||||
use crate::context_picker::ContextPicker;
|
use crate::context_picker::ContextPicker;
|
||||||
use crate::context_store::ContextStore;
|
use crate::context_store::ContextStore;
|
||||||
use crate::context_strip::ContextStrip;
|
use crate::context_strip::ContextStrip;
|
||||||
|
use crate::inline_prompt_editor::{CodegenStatus, PromptEditorEvent, PromptMode};
|
||||||
use crate::prompts::PromptBuilder;
|
use crate::prompts::PromptBuilder;
|
||||||
use crate::thread_store::ThreadStore;
|
use crate::thread_store::ThreadStore;
|
||||||
use crate::ToggleContextPicker;
|
use crate::ToggleContextPicker;
|
||||||
|
use crate::{assistant_settings::AssistantSettings, inline_prompt_editor::render_cancel_button};
|
||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
use client::telemetry::Telemetry;
|
use client::telemetry::Telemetry;
|
||||||
use collections::{HashMap, VecDeque};
|
use collections::{HashMap, VecDeque};
|
||||||
|
@ -448,15 +449,6 @@ impl TerminalInlineAssist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PromptEditorEvent {
|
|
||||||
StartRequested,
|
|
||||||
StopRequested,
|
|
||||||
ConfirmRequested { execute: bool },
|
|
||||||
CancelRequested,
|
|
||||||
DismissRequested,
|
|
||||||
Resized { height_in_lines: u8 },
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PromptEditor {
|
struct PromptEditor {
|
||||||
id: TerminalInlineAssistId,
|
id: TerminalInlineAssistId,
|
||||||
height_in_lines: u8,
|
height_in_lines: u8,
|
||||||
|
@ -477,104 +469,16 @@ impl EventEmitter<PromptEditorEvent> for PromptEditor {}
|
||||||
|
|
||||||
impl Render for PromptEditor {
|
impl Render for PromptEditor {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
let status = &self.codegen.read(cx).status;
|
|
||||||
let mut buttons = Vec::new();
|
let mut buttons = Vec::new();
|
||||||
|
|
||||||
buttons.extend(match status {
|
buttons.extend(render_cancel_button(
|
||||||
CodegenStatus::Idle => vec![
|
(&self.codegen.read(cx).status).into(),
|
||||||
IconButton::new("cancel", IconName::Close)
|
self.edited_since_done,
|
||||||
.icon_color(Color::Muted)
|
PromptMode::Generate {
|
||||||
.shape(IconButtonShape::Square)
|
supports_execute: true,
|
||||||
.tooltip(|cx| Tooltip::for_action("Cancel Assist", &menu::Cancel, cx))
|
},
|
||||||
.on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)))
|
|
||||||
.into_any_element(),
|
|
||||||
IconButton::new("start", IconName::SparkleAlt)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| Tooltip::for_action("Generate", &menu::Confirm, cx))
|
|
||||||
.on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StartRequested)))
|
|
||||||
.into_any_element(),
|
|
||||||
],
|
|
||||||
CodegenStatus::Pending => vec![
|
|
||||||
IconButton::new("cancel", IconName::Close)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| Tooltip::text("Cancel Assist", cx))
|
|
||||||
.on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)))
|
|
||||||
.into_any_element(),
|
|
||||||
IconButton::new("stop", IconName::Stop)
|
|
||||||
.icon_color(Color::Error)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| {
|
|
||||||
Tooltip::with_meta(
|
|
||||||
"Interrupt Generation",
|
|
||||||
Some(&menu::Cancel),
|
|
||||||
"Changes won't be discarded",
|
|
||||||
cx,
|
cx,
|
||||||
)
|
));
|
||||||
})
|
|
||||||
.on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StopRequested)))
|
|
||||||
.into_any_element(),
|
|
||||||
],
|
|
||||||
CodegenStatus::Error(_) | CodegenStatus::Done => {
|
|
||||||
let cancel = IconButton::new("cancel", IconName::Close)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| Tooltip::for_action("Cancel Assist", &menu::Cancel, cx))
|
|
||||||
.on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)))
|
|
||||||
.into_any_element();
|
|
||||||
|
|
||||||
let has_error = matches!(status, CodegenStatus::Error(_));
|
|
||||||
if has_error || self.edited_since_done {
|
|
||||||
vec![
|
|
||||||
cancel,
|
|
||||||
IconButton::new("restart", IconName::RotateCw)
|
|
||||||
.icon_color(Color::Info)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| {
|
|
||||||
Tooltip::with_meta(
|
|
||||||
"Restart Generation",
|
|
||||||
Some(&menu::Confirm),
|
|
||||||
"Changes will be discarded",
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.on_click(cx.listener(|_, _, cx| {
|
|
||||||
cx.emit(PromptEditorEvent::StartRequested);
|
|
||||||
}))
|
|
||||||
.into_any_element(),
|
|
||||||
]
|
|
||||||
} else {
|
|
||||||
vec![
|
|
||||||
cancel,
|
|
||||||
IconButton::new("accept", IconName::Check)
|
|
||||||
.icon_color(Color::Info)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| {
|
|
||||||
Tooltip::for_action("Accept Generated Command", &menu::Confirm, cx)
|
|
||||||
})
|
|
||||||
.on_click(cx.listener(|_, _, cx| {
|
|
||||||
cx.emit(PromptEditorEvent::ConfirmRequested { execute: false });
|
|
||||||
}))
|
|
||||||
.into_any_element(),
|
|
||||||
IconButton::new("confirm", IconName::Play)
|
|
||||||
.icon_color(Color::Info)
|
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.tooltip(|cx| {
|
|
||||||
Tooltip::for_action(
|
|
||||||
"Execute Generated Command",
|
|
||||||
&menu::SecondaryConfirm,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.on_click(cx.listener(|_, _, cx| {
|
|
||||||
cx.emit(PromptEditorEvent::ConfirmRequested { execute: true });
|
|
||||||
}))
|
|
||||||
.into_any_element(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.border_y_1()
|
.border_y_1()
|
||||||
|
@ -1097,10 +1001,3 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CodegenStatus {
|
|
||||||
Idle,
|
|
||||||
Pending,
|
|
||||||
Done,
|
|
||||||
Error(anyhow::Error),
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue