diff --git a/crates/ai/src/refactor.rs b/crates/ai/src/refactor.rs index 7b2f5a248a..58cd360186 100644 --- a/crates/ai/src/refactor.rs +++ b/crates/ai/src/refactor.rs @@ -3,10 +3,10 @@ use collections::HashMap; use editor::{Editor, ToOffset}; use futures::{channel::mpsc, SinkExt, StreamExt}; use gpui::{ - actions, elements::*, AnyViewHandle, AppContext, Entity, Task, View, ViewContext, ViewHandle, - WeakViewHandle, + actions, elements::*, platform::MouseButton, AnyViewHandle, AppContext, Entity, Task, View, + ViewContext, ViewHandle, WeakViewHandle, }; -use menu::Confirm; +use menu::{Cancel, Confirm}; use std::{env, sync::Arc}; use util::TryFutureExt; use workspace::{Modal, Workspace}; @@ -17,6 +17,7 @@ pub fn init(cx: &mut AppContext) { cx.set_global(RefactoringAssistant::new()); cx.add_action(RefactoringModal::deploy); cx.add_action(RefactoringModal::confirm); + cx.add_action(RefactoringModal::cancel); } pub struct RefactoringAssistant { @@ -139,14 +140,18 @@ impl RefactoringAssistant { } } +enum Event { + Dismissed, +} + struct RefactoringModal { - editor: WeakViewHandle, + active_editor: WeakViewHandle, prompt_editor: ViewHandle, has_focus: bool, } impl Entity for RefactoringModal { - type Event = (); + type Event = Event; } impl View for RefactoringModal { @@ -155,11 +160,24 @@ impl View for RefactoringModal { } fn render(&mut self, cx: &mut ViewContext) -> AnyElement { - ChildView::new(&self.prompt_editor, cx).into_any() + let theme = theme::current(cx); + + ChildView::new(&self.prompt_editor, cx) + .constrained() + .with_width(theme.assistant.modal.width) + .contained() + .with_style(theme.assistant.modal.container) + .mouse::(0) + .on_click_out(MouseButton::Left, |_, _, cx| cx.emit(Event::Dismissed)) + .on_click_out(MouseButton::Right, |_, _, cx| cx.emit(Event::Dismissed)) + .aligned() + .right() + .into_any() } - fn focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { self.has_focus = true; + cx.focus(&self.prompt_editor); } fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext) { @@ -173,29 +191,29 @@ impl Modal for RefactoringModal { } fn dismiss_on_event(event: &Self::Event) -> bool { - // TODO - false + matches!(event, Self::Event::Dismissed) } } impl RefactoringModal { fn deploy(workspace: &mut Workspace, _: &Refactor, cx: &mut ViewContext) { - if let Some(editor) = workspace + if let Some(active_editor) = workspace .active_item(cx) .and_then(|item| Some(item.downcast::()?.downgrade())) { workspace.toggle_modal(cx, |_, cx| { let prompt_editor = cx.add_view(|cx| { let mut editor = Editor::auto_height( - 4, - Some(Arc::new(|theme| theme.search.editor.input.clone())), + theme::current(cx).assistant.modal.editor_max_lines, + Some(Arc::new(|theme| theme.assistant.modal.editor.clone())), cx, ); - editor.set_text("Replace with if statement.", cx); + editor + .set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx); editor }); cx.add_view(|_| RefactoringModal { - editor, + active_editor, prompt_editor, has_focus: false, }) @@ -203,12 +221,17 @@ impl RefactoringModal { } } + fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) { + cx.emit(Event::Dismissed); + } + fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext) { - if let Some(editor) = self.editor.upgrade(cx) { + if let Some(editor) = self.active_editor.upgrade(cx) { let prompt = self.prompt_editor.read(cx).text(cx); cx.update_global(|assistant: &mut RefactoringAssistant, cx| { assistant.refactor(&editor, &prompt, cx); }); + cx.emit(Event::Dismissed); } } } diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 80e823632a..a42a893241 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -1124,6 +1124,16 @@ pub struct AssistantStyle { pub api_key_editor: FieldEditor, pub api_key_prompt: ContainedText, pub saved_conversation: SavedConversation, + pub modal: ModalAssistantStyle, +} + +#[derive(Clone, Deserialize, Default, JsonSchema)] +pub struct ModalAssistantStyle { + #[serde(flatten)] + pub container: ContainerStyle, + pub width: f32, + pub editor_max_lines: usize, + pub editor: FieldEditor, } #[derive(Clone, Deserialize, Default, JsonSchema)] diff --git a/styles/src/style_tree/assistant.ts b/styles/src/style_tree/assistant.ts index cfc1f8d813..88efabee1e 100644 --- a/styles/src/style_tree/assistant.ts +++ b/styles/src/style_tree/assistant.ts @@ -59,6 +59,22 @@ export default function assistant(): any { background: background(theme.highest), padding: { left: 12 }, }, + modal: { + background: background(theme.lowest), + border: border(theme.lowest), + shadow: theme.modal_shadow, + corner_radius: 12, + padding: { left: 12, right: 0, top: 12, bottom: 12 }, + margin: { right: 12 }, + width: 500, + editor_max_lines: 6, + editor: { + background: background(theme.lowest), + text: text(theme.lowest, "mono", "on"), + placeholder_text: text(theme.lowest, "sans", "on", "disabled"), + selection: theme.players[0], + } + }, message_header: { margin: { bottom: 4, top: 4 }, background: background(theme.highest),