diff --git a/Cargo.lock b/Cargo.lock index fea2808632..45fe7ad8e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1725,6 +1725,7 @@ version = "0.1.0" dependencies = [ "editor", "gpui", + "postage", "workspace", ] diff --git a/crates/find/Cargo.toml b/crates/find/Cargo.toml index 94ac64fcf7..08805a67d3 100644 --- a/crates/find/Cargo.toml +++ b/crates/find/Cargo.toml @@ -10,3 +10,4 @@ path = "src/find.rs" editor = { path = "../editor" } gpui = { path = "../gpui" } workspace = { path = "../workspace" } +postage = { version = "0.4.1", features = ["futures-traits"] } diff --git a/crates/find/src/find.rs b/crates/find/src/find.rs index b8949703ff..6c43725a4a 100644 --- a/crates/find/src/find.rs +++ b/crates/find/src/find.rs @@ -1,8 +1,11 @@ +use editor::{Editor, EditorSettings}; use gpui::{ - action, color::Color, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, - View, ViewContext, + action, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, View, + ViewContext, ViewHandle, }; -use workspace::Workspace; +use postage::watch; +use std::sync::Arc; +use workspace::{ItemViewHandle, Settings, Toolbar, Workspace}; action!(Deploy); @@ -15,7 +18,11 @@ pub fn init(cx: &mut MutableAppContext) { cx.add_action(FindBar::deploy); } -struct FindBar; +struct FindBar { + settings: watch::Receiver, + query_editor: ViewHandle, + active_editor: Option>, +} impl Entity for FindBar { type Event = (); @@ -27,19 +34,65 @@ impl View for FindBar { } fn render(&mut self, _: &mut RenderContext) -> ElementBox { - Empty::new() + ChildView::new(&self.query_editor) .contained() - .with_background_color(Color::red()) - .constrained() - .with_height(30.) + .with_style(self.settings.borrow().theme.selector.input_editor.container) .boxed() } } -impl FindBar { - fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext) { - workspace - .active_pane() - .update(cx, |pane, cx| pane.show_toolbar(cx, |_| FindBar)); +impl Toolbar for FindBar { + fn active_item_changed( + &mut self, + item: Option>, + cx: &mut ViewContext, + ) -> bool { + self.active_editor = item.and_then(|item| item.act_as::(cx)); + self.active_editor.is_some() + } +} + +impl FindBar { + fn new(settings: watch::Receiver, cx: &mut ViewContext) -> Self { + let query_editor = cx.add_view(|cx| { + Editor::single_line( + { + let settings = settings.clone(); + Arc::new(move |_| { + let settings = settings.borrow(); + EditorSettings { + style: settings.theme.selector.input_editor.as_editor(), + tab_size: settings.tab_size, + soft_wrap: editor::SoftWrap::None, + } + }) + }, + cx, + ) + }); + cx.subscribe(&query_editor, Self::on_query_editor_event) + .detach(); + + Self { + query_editor, + active_editor: None, + settings, + } + } + + fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext) { + let settings = workspace.settings(); + workspace.active_pane().update(cx, |pane, cx| { + pane.show_toolbar(cx, |cx| FindBar::new(settings, cx)); + if let Some(toolbar) = pane.active_toolbar() { + cx.focus(toolbar); + } + }); + } + + fn cancel(workspace: &mut Workspace, _: &Cancel, cx: &mut ViewContext) { + workspace + .active_pane() + .update(cx, |pane, cx| pane.hide_toolbar(cx)); } } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 95fb7c863b..5cbd9fe559 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -81,14 +81,27 @@ pub struct Pane { active_item_index: usize, settings: watch::Receiver, nav_history: Rc>, - toolbars: HashMap, - active_toolbar: Option, + toolbars: HashMap>, + active_toolbar_type: Option, + active_toolbar_visible: bool, } -// #[derive(Debug, Eq, PartialEq)] -// pub struct State { -// pub tabs: Vec, -// } +pub trait Toolbar: View { + fn active_item_changed( + &mut self, + item: Option>, + cx: &mut ViewContext, + ) -> bool; +} + +trait ToolbarHandle { + fn active_item_changed( + &self, + item: Option>, + cx: &mut MutableAppContext, + ) -> bool; + fn to_any(&self) -> AnyViewHandle; +} pub struct ItemNavHistory { history: Rc>, @@ -129,7 +142,8 @@ impl Pane { settings, nav_history: Default::default(), toolbars: Default::default(), - active_toolbar: Default::default(), + active_toolbar_type: Default::default(), + active_toolbar_visible: false, } } @@ -301,6 +315,7 @@ impl Pane { if prev_active_item_ix != self.active_item_index { self.item_views[prev_active_item_ix].1.deactivated(cx); } + self.update_active_toolbar(cx); self.focus_active_item(cx); cx.notify(); } @@ -354,15 +369,18 @@ impl Pane { true } }); - self.active_item_index = cmp::min( - self.active_item_index, - self.item_views.len().saturating_sub(1), + self.activate_item( + cmp::min( + self.active_item_index, + self.item_views.len().saturating_sub(1), + ), + cx, ); if self.item_views.is_empty() { + self.update_active_toolbar(cx); cx.emit(Event::Remove); } - cx.notify(); } fn focus_active_item(&mut self, cx: &mut ViewContext) { @@ -378,16 +396,46 @@ impl Pane { pub fn show_toolbar(&mut self, cx: &mut ViewContext, build_toolbar: F) where F: FnOnce(&mut ViewContext) -> V, - V: View, + V: Toolbar, { - let handle = self - .toolbars - .entry(TypeId::of::()) - .or_insert_with(|| cx.add_view(build_toolbar).into()); - self.active_toolbar = Some(handle.clone()); + let type_id = TypeId::of::(); + let active_item = self.active_item(); + self.toolbars + .entry(type_id) + .or_insert_with(|| Box::new(cx.add_view(build_toolbar))); + self.active_toolbar_type = Some(type_id); + self.active_toolbar_visible = self.toolbars[&type_id].active_item_changed(active_item, cx); cx.notify(); } + pub fn hide_toolbar(&mut self, cx: &mut ViewContext) { + self.active_toolbar_type = None; + self.active_toolbar_visible = false; + self.focus_active_item(cx); + cx.notify(); + } + + pub fn active_toolbar(&self) -> Option { + let type_id = self.active_toolbar_type?; + let toolbar = self.toolbars.get(&type_id)?; + if self.active_toolbar_visible { + Some(toolbar.to_any()) + } else { + None + } + } + + fn update_active_toolbar(&mut self, cx: &mut ViewContext) { + if let Some(type_id) = self.active_toolbar_type { + if let Some(toolbar) = self.toolbars.get(&type_id) { + self.active_toolbar_visible = toolbar.active_item_changed( + Some(self.item_views[self.active_item_index].1.clone()), + cx, + ); + } + } + } + fn render_tabs(&self, cx: &mut RenderContext) -> ElementBox { let settings = self.settings.borrow(); let theme = &settings.theme; @@ -540,7 +588,7 @@ impl View for Pane { Flex::column() .with_child(self.render_tabs(cx)) .with_children( - self.active_toolbar + self.active_toolbar() .as_ref() .map(|view| ChildView::new(view).boxed()), ) @@ -556,6 +604,20 @@ impl View for Pane { } } +impl ToolbarHandle for ViewHandle { + fn active_item_changed( + &self, + item: Option>, + cx: &mut MutableAppContext, + ) -> bool { + self.update(cx, |this, cx| this.active_item_changed(item, cx)) + } + + fn to_any(&self) -> AnyViewHandle { + self.into() + } +} + impl ItemNavHistory { pub fn new(history: Rc>, item_view: &ViewHandle) -> Self { Self {