Detailed changes
@@ -8,7 +8,7 @@ use gpui::{
use language::OffsetRangeExt;
use project::search::SearchQuery;
use std::ops::Range;
-use workspace::{ItemHandle, Pane, Settings, Toolbar, Workspace};
+use workspace::{ItemHandle, Pane, Settings, ToolbarItemView};
action!(Deploy, bool);
action!(Dismiss);
@@ -38,7 +38,7 @@ pub fn init(cx: &mut MutableAppContext) {
cx.add_action(SearchBar::select_match_on_pane);
}
-struct SearchBar {
+pub struct SearchBar {
query_editor: ViewHandle<Editor>,
active_editor: Option<ViewHandle<Editor>>,
active_match_index: Option<usize>,
@@ -66,69 +66,69 @@ impl View for SearchBar {
}
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
- let theme = cx.global::<Settings>().theme.clone();
- let editor_container = if self.query_contains_error {
- theme.search.invalid_editor
+ if self.dismissed {
+ Empty::new().boxed()
} else {
- theme.search.editor.input.container
- };
- Flex::row()
- .with_child(
- ChildView::new(&self.query_editor)
- .contained()
- .with_style(editor_container)
- .aligned()
- .constrained()
- .with_max_width(theme.search.editor.max_width)
- .boxed(),
- )
- .with_child(
- Flex::row()
- .with_child(self.render_search_option("Case", SearchOption::CaseSensitive, cx))
- .with_child(self.render_search_option("Word", SearchOption::WholeWord, cx))
- .with_child(self.render_search_option("Regex", SearchOption::Regex, cx))
- .contained()
- .with_style(theme.search.option_button_group)
- .aligned()
- .boxed(),
- )
- .with_child(
- Flex::row()
- .with_child(self.render_nav_button("<", Direction::Prev, cx))
- .with_child(self.render_nav_button(">", Direction::Next, cx))
- .aligned()
- .boxed(),
- )
- .with_children(self.active_editor.as_ref().and_then(|editor| {
- let matches = self.editors_with_matches.get(&editor.downgrade())?;
- let message = if let Some(match_ix) = self.active_match_index {
- format!("{}/{}", match_ix + 1, matches.len())
- } else {
- "No matches".to_string()
- };
-
- Some(
- Label::new(message, theme.search.match_index.text.clone())
+ let theme = cx.global::<Settings>().theme.clone();
+ let editor_container = if self.query_contains_error {
+ theme.search.invalid_editor
+ } else {
+ theme.search.editor.container
+ };
+ Flex::row()
+ .with_child(
+ ChildView::new(&self.query_editor)
.contained()
- .with_style(theme.search.match_index.container)
+ .with_style(editor_container)
.aligned()
+ .constrained()
+ .with_max_width(theme.search.max_editor_width)
.boxed(),
)
- }))
- .contained()
- .with_style(theme.search.container)
- .constrained()
- .with_height(theme.workspace.toolbar.height)
- .named("search bar")
+ .with_child(
+ Flex::row()
+ .with_child(self.render_search_option(
+ "Case",
+ SearchOption::CaseSensitive,
+ cx,
+ ))
+ .with_child(self.render_search_option("Word", SearchOption::WholeWord, cx))
+ .with_child(self.render_search_option("Regex", SearchOption::Regex, cx))
+ .contained()
+ .with_style(theme.search.option_button_group)
+ .aligned()
+ .boxed(),
+ )
+ .with_child(
+ Flex::row()
+ .with_child(self.render_nav_button("<", Direction::Prev, cx))
+ .with_child(self.render_nav_button(">", Direction::Next, cx))
+ .aligned()
+ .boxed(),
+ )
+ .with_children(self.active_editor.as_ref().and_then(|editor| {
+ let matches = self.editors_with_matches.get(&editor.downgrade())?;
+ let message = if let Some(match_ix) = self.active_match_index {
+ format!("{}/{}", match_ix + 1, matches.len())
+ } else {
+ "No matches".to_string()
+ };
+
+ Some(
+ Label::new(message, theme.search.match_index.text.clone())
+ .contained()
+ .with_style(theme.search.match_index.container)
+ .aligned()
+ .boxed(),
+ )
+ }))
+ .named("search bar")
+ }
}
}
-impl Toolbar for SearchBar {
- fn active_item_changed(
- &mut self,
- item: Option<Box<dyn ItemHandle>>,
- cx: &mut ViewContext<Self>,
- ) -> bool {
+impl ToolbarItemView for SearchBar {
+ fn set_active_pane_item(&mut self, item: Option<&dyn ItemHandle>, cx: &mut ViewContext<Self>) {
self.active_editor_subscription.take();
self.active_editor.take();
self.pending_search.take();
@@ -139,29 +139,19 @@ impl Toolbar for SearchBar {
Some(cx.subscribe(&editor, Self::on_active_editor_event));
self.active_editor = Some(editor);
self.update_matches(false, cx);
- return true;
+ self.dismissed = false;
+ return;
}
}
- false
- }
- fn on_dismiss(&mut self, cx: &mut ViewContext<Self>) {
- self.dismissed = true;
- for (editor, _) in &self.editors_with_matches {
- if let Some(editor) = editor.upgrade(cx) {
- editor.update(cx, |editor, cx| {
- editor.clear_background_highlights::<Self>(cx)
- });
- }
- }
+ self.dismiss(&Dismiss, cx);
}
}
impl SearchBar {
- fn new(cx: &mut ViewContext<Self>) -> Self {
- let query_editor = cx.add_view(|cx| {
- Editor::auto_height(2, Some(|theme| theme.search.editor.input.clone()), cx)
- });
+ pub fn new(cx: &mut ViewContext<Self>) -> Self {
+ let query_editor =
+ cx.add_view(|cx| Editor::auto_height(2, Some(|theme| theme.search.editor.clone()), cx));
cx.subscribe(&query_editor, Self::on_query_editor_event)
.detach();
@@ -176,10 +166,73 @@ impl SearchBar {
regex: false,
pending_search: None,
query_contains_error: false,
- dismissed: false,
+ dismissed: true,
}
}
+ fn dismiss(&mut self, _: &Dismiss, cx: &mut ViewContext<Self>) {
+ self.dismissed = true;
+ for (editor, _) in &self.editors_with_matches {
+ if let Some(editor) = editor.upgrade(cx) {
+ editor.update(cx, |editor, cx| {
+ editor.clear_background_highlights::<Self>(cx)
+ });
+ }
+ }
+ if let Some(active_editor) = self.active_editor.as_ref() {
+ cx.focus(active_editor);
+ }
+ cx.notify();
+ }
+
+ fn show(&mut self, focus: bool, cx: &mut ViewContext<Self>) -> bool {
+ let editor = if let Some(editor) = self.active_editor.clone() {
+ editor
+ } else {
+ return false;
+ };
+
+ let display_map = editor
+ .update(cx, |editor, cx| editor.snapshot(cx))
+ .display_snapshot;
+ let selection = editor
+ .read(cx)
+ .newest_selection_with_snapshot::<usize>(&display_map.buffer_snapshot);
+
+ let mut text: String;
+ if selection.start == selection.end {
+ let point = selection.start.to_display_point(&display_map);
+ let range = editor::movement::surrounding_word(&display_map, point);
+ let range = range.start.to_offset(&display_map, Bias::Left)
+ ..range.end.to_offset(&display_map, Bias::Right);
+ text = display_map.buffer_snapshot.text_for_range(range).collect();
+ if text.trim().is_empty() {
+ text = String::new();
+ }
+ } else {
+ text = display_map
+ .buffer_snapshot
+ .text_for_range(selection.start..selection.end)
+ .collect();
+ }
+
+ if !text.is_empty() {
+ self.set_query(&text, cx);
+ }
+
+ if focus {
+ let query_editor = self.query_editor.clone();
+ query_editor.update(cx, |query_editor, cx| {
+ query_editor.select_all(&editor::SelectAll, cx);
+ });
+ cx.focus_self();
+ }
+
+ self.dismissed = false;
+ cx.notify();
+ true
+ }
+
fn set_query(&mut self, query: &str, cx: &mut ViewContext<Self>) {
self.query_editor.update(cx, |query_editor, cx| {
query_editor.buffer().update(cx, |query_buffer, cx| {
@@ -238,61 +291,13 @@ impl SearchBar {
.boxed()
}
- fn deploy(workspace: &mut Workspace, Deploy(focus): &Deploy, cx: &mut ViewContext<Workspace>) {
- workspace.active_pane().update(cx, |pane, cx| {
- pane.show_toolbar(cx, |cx| SearchBar::new(cx));
-
- if let Some(search_bar) = pane
- .active_toolbar()
- .and_then(|toolbar| toolbar.downcast::<Self>())
- {
- search_bar.update(cx, |search_bar, _| search_bar.dismissed = false);
- let editor = pane.active_item().unwrap().act_as::<Editor>(cx).unwrap();
- let display_map = editor
- .update(cx, |editor, cx| editor.snapshot(cx))
- .display_snapshot;
- let selection = editor
- .read(cx)
- .newest_selection_with_snapshot::<usize>(&display_map.buffer_snapshot);
-
- let mut text: String;
- if selection.start == selection.end {
- let point = selection.start.to_display_point(&display_map);
- let range = editor::movement::surrounding_word(&display_map, point);
- let range = range.start.to_offset(&display_map, Bias::Left)
- ..range.end.to_offset(&display_map, Bias::Right);
- text = display_map.buffer_snapshot.text_for_range(range).collect();
- if text.trim().is_empty() {
- text = String::new();
- }
- } else {
- text = display_map
- .buffer_snapshot
- .text_for_range(selection.start..selection.end)
- .collect();
- }
-
- if !text.is_empty() {
- search_bar.update(cx, |search_bar, cx| search_bar.set_query(&text, cx));
- }
-
- if *focus {
- let query_editor = search_bar.read(cx).query_editor.clone();
- query_editor.update(cx, |query_editor, cx| {
- query_editor.select_all(&editor::SelectAll, cx);
- });
- cx.focus(&search_bar);
- }
- } else {
- cx.propagate_action();
+ fn deploy(pane: &mut Pane, Deploy(focus): &Deploy, cx: &mut ViewContext<Pane>) {
+ if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<SearchBar>() {
+ if search_bar.update(cx, |search_bar, cx| search_bar.show(*focus, cx)) {
+ return;
}
- });
- }
-
- fn dismiss(pane: &mut Pane, _: &Dismiss, cx: &mut ViewContext<Pane>) {
- if pane.toolbar::<SearchBar>().is_some() {
- pane.dismiss_toolbar(cx);
}
+ cx.propagate_action();
}
fn focus_editor(&mut self, _: &FocusEditor, cx: &mut ViewContext<Self>) {
@@ -346,7 +351,7 @@ impl SearchBar {
}
fn select_match_on_pane(pane: &mut Pane, action: &SelectMatch, cx: &mut ViewContext<Pane>) {
- if let Some(search_bar) = pane.toolbar::<SearchBar>() {
+ if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<SearchBar>() {
search_bar.update(cx, |search_bar, cx| search_bar.select_match(action, cx));
}
}
@@ -541,7 +546,7 @@ mod tests {
let search_bar = cx.add_view(Default::default(), |cx| {
let mut search_bar = SearchBar::new(cx);
- search_bar.active_item_changed(Some(Box::new(editor.clone())), cx);
+ search_bar.set_active_pane_item(Some(&editor), cx);
search_bar
});
@@ -336,8 +336,7 @@ impl ProjectSearchView {
.detach();
let query_editor = cx.add_view(|cx| {
- let mut editor =
- Editor::single_line(Some(|theme| theme.search.editor.input.clone()), cx);
+ let mut editor = Editor::single_line(Some(|theme| theme.search.editor.clone()), cx);
editor.set_text(query_text, cx);
editor
});
@@ -569,7 +568,7 @@ impl ProjectSearchView {
let editor_container = if self.query_contains_error {
theme.search.invalid_editor
} else {
- theme.search.editor.input.container
+ theme.search.editor.container
};
Flex::row()
.with_child(
@@ -578,7 +577,7 @@ impl ProjectSearchView {
.with_style(editor_container)
.aligned()
.constrained()
- .with_max_width(theme.search.editor.max_width)
+ .with_max_width(theme.search.max_editor_width)
.boxed(),
)
.with_child(
@@ -615,7 +614,7 @@ impl ProjectSearchView {
})
})
.contained()
- .with_style(theme.search.container)
+ .with_style(theme.workspace.toolbar.container)
.constrained()
.with_height(theme.workspace.toolbar.height)
.named("project search")
@@ -1,11 +1,11 @@
+pub use buffer_search::SearchBar;
+use editor::{Anchor, MultiBufferSnapshot};
+use gpui::{action, MutableAppContext};
use std::{
cmp::{self, Ordering},
ops::Range,
};
-use editor::{Anchor, MultiBufferSnapshot};
-use gpui::{action, MutableAppContext};
-
mod buffer_search;
mod project_search;
@@ -94,14 +94,18 @@ pub struct Tab {
#[derive(Clone, Deserialize, Default)]
pub struct Toolbar {
+ #[serde(flatten)]
+ pub container: ContainerStyle,
pub height: f32,
+ pub item_spacing: f32,
}
#[derive(Clone, Deserialize, Default)]
pub struct Search {
#[serde(flatten)]
pub container: ContainerStyle,
- pub editor: FindEditor,
+ pub max_editor_width: f32,
+ pub editor: FieldEditor,
pub invalid_editor: ContainerStyle,
pub option_button_group: ContainerStyle,
pub option_button: ContainedText,
@@ -115,13 +119,6 @@ pub struct Search {
pub tab_icon_spacing: f32,
}
-#[derive(Clone, Deserialize, Default)]
-pub struct FindEditor {
- #[serde(flatten)]
- pub input: FieldEditor,
- pub max_width: f32,
-}
-
#[derive(Deserialize, Default)]
pub struct Sidebar {
#[serde(flatten)]
@@ -1,5 +1,5 @@
use super::{ItemHandle, SplitDirection};
-use crate::{Item, Settings, WeakItemHandle, Workspace};
+use crate::{toolbar::Toolbar, Item, Settings, WeakItemHandle, Workspace};
use collections::{HashMap, VecDeque};
use gpui::{
action,
@@ -7,16 +7,11 @@ use gpui::{
geometry::{rect::RectF, vector::vec2f},
keymap::Binding,
platform::{CursorStyle, NavigationDirection},
- AnyViewHandle, AppContext, Entity, MutableAppContext, Quad, RenderContext, Task, View,
- ViewContext, ViewHandle, WeakViewHandle,
+ AppContext, Entity, MutableAppContext, Quad, RenderContext, Task, View, ViewContext,
+ ViewHandle, WeakViewHandle,
};
use project::{ProjectEntryId, ProjectPath};
-use std::{
- any::{Any, TypeId},
- cell::RefCell,
- cmp, mem,
- rc::Rc,
-};
+use std::{any::Any, cell::RefCell, cmp, mem, rc::Rc};
use util::ResultExt;
action!(Split, SplitDirection);
@@ -101,28 +96,7 @@ pub struct Pane {
items: Vec<Box<dyn ItemHandle>>,
active_item_index: usize,
nav_history: Rc<RefCell<NavHistory>>,
- toolbars: HashMap<TypeId, Box<dyn ToolbarHandle>>,
- active_toolbar_type: Option<TypeId>,
- active_toolbar_visible: bool,
-}
-
-pub trait Toolbar: View {
- fn active_item_changed(
- &mut self,
- item: Option<Box<dyn ItemHandle>>,
- cx: &mut ViewContext<Self>,
- ) -> bool;
- fn on_dismiss(&mut self, cx: &mut ViewContext<Self>);
-}
-
-trait ToolbarHandle {
- fn active_item_changed(
- &self,
- item: Option<Box<dyn ItemHandle>>,
- cx: &mut MutableAppContext,
- ) -> bool;
- fn on_dismiss(&self, cx: &mut MutableAppContext);
- fn to_any(&self) -> AnyViewHandle;
+ toolbar: ViewHandle<Toolbar>,
}
pub struct ItemNavHistory {
@@ -158,14 +132,12 @@ pub struct NavigationEntry {
}
impl Pane {
- pub fn new() -> Self {
+ pub fn new(cx: &mut ViewContext<Self>) -> Self {
Self {
items: Vec::new(),
active_item_index: 0,
nav_history: Default::default(),
- toolbars: Default::default(),
- active_toolbar_type: Default::default(),
- active_toolbar_visible: false,
+ toolbar: cx.add_view(|_| Toolbar::new()),
}
}
@@ -402,7 +374,7 @@ impl Pane {
self.items[prev_active_item_ix].deactivated(cx);
cx.emit(Event::ActivateItem { local });
}
- self.update_active_toolbar(cx);
+ self.update_toolbar(cx);
if local {
self.focus_active_item(cx);
self.activate(cx);
@@ -487,7 +459,7 @@ impl Pane {
self.focus_active_item(cx);
self.activate(cx);
}
- self.update_active_toolbar(cx);
+ self.update_toolbar(cx);
cx.notify();
}
@@ -502,63 +474,18 @@ impl Pane {
cx.emit(Event::Split(direction));
}
- pub fn show_toolbar<F, V>(&mut self, cx: &mut ViewContext<Self>, build_toolbar: F)
- where
- F: FnOnce(&mut ViewContext<V>) -> V,
- V: Toolbar,
- {
- let type_id = TypeId::of::<V>();
- if self.active_toolbar_type != Some(type_id) {
- self.dismiss_toolbar(cx);
-
- 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 dismiss_toolbar(&mut self, cx: &mut ViewContext<Self>) {
- if let Some(active_toolbar_type) = self.active_toolbar_type.take() {
- self.toolbars
- .get_mut(&active_toolbar_type)
- .unwrap()
- .on_dismiss(cx);
- self.active_toolbar_visible = false;
- self.focus_active_item(cx);
- cx.notify();
- }
+ pub fn toolbar(&self) -> &ViewHandle<Toolbar> {
+ &self.toolbar
}
- pub fn toolbar<T: Toolbar>(&self) -> Option<ViewHandle<T>> {
- self.toolbars
- .get(&TypeId::of::<T>())
- .and_then(|toolbar| toolbar.to_any().downcast())
- }
-
- pub fn active_toolbar(&self) -> Option<AnyViewHandle> {
- 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<Self>) {
- let active_item = self.items.get(self.active_item_index);
- for (toolbar_type_id, toolbar) in &self.toolbars {
- let visible = toolbar.active_item_changed(active_item.cloned(), cx);
- if Some(*toolbar_type_id) == self.active_toolbar_type {
- self.active_toolbar_visible = visible;
- }
- }
+ fn update_toolbar(&mut self, cx: &mut ViewContext<Self>) {
+ let active_item = self
+ .items
+ .get(self.active_item_index)
+ .map(|item| item.as_ref());
+ self.toolbar.update(cx, |toolbar, cx| {
+ toolbar.set_active_pane_item(active_item, cx);
+ });
}
fn render_tabs(&self, cx: &mut RenderContext<Self>) -> ElementBox {
@@ -713,11 +640,7 @@ impl View for Pane {
EventHandler::new(if let Some(active_item) = self.active_item() {
Flex::column()
.with_child(self.render_tabs(cx))
- .with_children(
- self.active_toolbar()
- .as_ref()
- .map(|view| ChildView::new(view).boxed()),
- )
+ .with_child(ChildView::new(&self.toolbar).boxed())
.with_child(ChildView::new(active_item).flexible(1., true).boxed())
.boxed()
} else {
@@ -740,24 +663,6 @@ impl View for Pane {
}
}
-impl<T: Toolbar> ToolbarHandle for ViewHandle<T> {
- fn active_item_changed(
- &self,
- item: Option<Box<dyn ItemHandle>>,
- cx: &mut MutableAppContext,
- ) -> bool {
- self.update(cx, |this, cx| this.active_item_changed(item, cx))
- }
-
- fn on_dismiss(&self, cx: &mut MutableAppContext) {
- self.update(cx, |this, cx| this.on_dismiss(cx));
- }
-
- fn to_any(&self) -> AnyViewHandle {
- self.into()
- }
-}
-
impl ItemNavHistory {
pub fn new<T: Item>(history: Rc<RefCell<NavHistory>>, item: &ViewHandle<T>) -> Self {
Self {
@@ -0,0 +1,131 @@
+use crate::{ItemHandle, Settings};
+use gpui::{
+ elements::*, AnyViewHandle, ElementBox, Entity, MutableAppContext, RenderContext, View,
+ ViewContext, ViewHandle,
+};
+
+pub trait ToolbarItemView: View {
+ fn set_active_pane_item(
+ &mut self,
+ active_pane_item: Option<&dyn crate::ItemHandle>,
+ cx: &mut ViewContext<Self>,
+ );
+}
+
+trait ToolbarItemViewHandle {
+ fn to_any(&self) -> AnyViewHandle;
+ fn set_active_pane_item(
+ &self,
+ active_pane_item: Option<&dyn ItemHandle>,
+ cx: &mut MutableAppContext,
+ );
+}
+
+pub struct Toolbar {
+ active_pane_item: Option<Box<dyn ItemHandle>>,
+ left_items: Vec<Box<dyn ToolbarItemViewHandle>>,
+ right_items: Vec<Box<dyn ToolbarItemViewHandle>>,
+}
+
+impl Entity for Toolbar {
+ type Event = ();
+}
+
+impl View for Toolbar {
+ fn ui_name() -> &'static str {
+ "Toolbar"
+ }
+
+ fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+ let theme = &cx.global::<Settings>().theme.workspace.toolbar;
+ Flex::row()
+ .with_children(self.left_items.iter().map(|i| {
+ ChildView::new(i.as_ref())
+ .aligned()
+ .contained()
+ .with_margin_right(theme.item_spacing)
+ .boxed()
+ }))
+ .with_child(Empty::new().flexible(1., true).boxed())
+ .with_children(self.right_items.iter().map(|i| {
+ ChildView::new(i.as_ref())
+ .aligned()
+ .contained()
+ .with_margin_left(theme.item_spacing)
+ .boxed()
+ }))
+ .contained()
+ .with_style(theme.container)
+ .constrained()
+ .with_height(theme.height)
+ .boxed()
+ }
+}
+
+impl Toolbar {
+ pub fn new() -> Self {
+ Self {
+ active_pane_item: None,
+ left_items: Default::default(),
+ right_items: Default::default(),
+ }
+ }
+
+ pub fn add_left_item<T>(&mut self, item: ViewHandle<T>, cx: &mut ViewContext<Self>)
+ where
+ T: 'static + ToolbarItemView,
+ {
+ item.set_active_pane_item(self.active_pane_item.as_deref(), cx);
+ self.left_items.push(Box::new(item));
+ cx.notify();
+ }
+
+ pub fn add_right_item<T>(&mut self, item: ViewHandle<T>, cx: &mut ViewContext<Self>)
+ where
+ T: 'static + ToolbarItemView,
+ {
+ item.set_active_pane_item(self.active_pane_item.as_deref(), cx);
+ self.right_items.push(Box::new(item));
+ cx.notify();
+ }
+
+ pub fn set_active_pane_item(
+ &mut self,
+ item: Option<&dyn ItemHandle>,
+ cx: &mut ViewContext<Self>,
+ ) {
+ self.active_pane_item = item.map(|item| item.boxed_clone());
+ for tool in self.left_items.iter().chain(&self.right_items) {
+ tool.set_active_pane_item(item, cx);
+ }
+ }
+
+ pub fn item_of_type<T: ToolbarItemView>(&self) -> Option<ViewHandle<T>> {
+ self.left_items
+ .iter()
+ .chain(&self.right_items)
+ .find_map(|tool| tool.to_any().downcast())
+ }
+}
+
+impl<T: ToolbarItemView> ToolbarItemViewHandle for ViewHandle<T> {
+ fn to_any(&self) -> AnyViewHandle {
+ self.into()
+ }
+
+ fn set_active_pane_item(
+ &self,
+ active_pane_item: Option<&dyn ItemHandle>,
+ cx: &mut MutableAppContext,
+ ) {
+ self.update(cx, |this, cx| {
+ this.set_active_pane_item(active_pane_item, cx)
+ });
+ }
+}
+
+impl Into<AnyViewHandle> for &dyn ToolbarItemViewHandle {
+ fn into(self) -> AnyViewHandle {
+ self.to_any()
+ }
+}
@@ -5,6 +5,7 @@ pub mod pane_group;
pub mod settings;
pub mod sidebar;
mod status_bar;
+mod toolbar;
use anyhow::{anyhow, Context, Result};
use client::{
@@ -47,6 +48,7 @@ use std::{
},
};
use theme::{Theme, ThemeRegistry};
+pub use toolbar::ToolbarItemView;
use util::ResultExt;
type ProjectItemBuilders = HashMap<
@@ -720,7 +722,7 @@ impl Workspace {
})
.detach();
- let pane = cx.add_view(|_| Pane::new());
+ let pane = cx.add_view(|cx| Pane::new(cx));
let pane_id = pane.id();
cx.observe(&pane, move |me, _, cx| {
let active_entry = me.active_project_path(cx);
@@ -733,6 +735,7 @@ impl Workspace {
})
.detach();
cx.focus(&pane);
+ cx.emit(Event::PaneAdded(pane.clone()));
let status_bar = cx.add_view(|cx| StatusBar::new(&pane, cx));
let mut current_user = params.user_store.read(cx).watch_current_user().clone();
@@ -1051,7 +1054,7 @@ impl Workspace {
}
fn add_pane(&mut self, cx: &mut ViewContext<Self>) -> ViewHandle<Pane> {
- let pane = cx.add_view(|_| Pane::new());
+ let pane = cx.add_view(|cx| Pane::new(cx));
let pane_id = pane.id();
cx.observe(&pane, move |me, _, cx| {
let active_entry = me.active_project_path(cx);
@@ -85,7 +85,10 @@ diagnostic_message = "$text.2"
lsp_message = "$text.2"
[workspace.toolbar]
+background = "$surface.1"
+border = { color = "$border.0", width = 1, left = false, right = false, bottom = true, top = false }
height = 44
+item_spacing = 8
[panel]
padding = { top = 12, left = 12, bottom = 12, right = 12 }
@@ -353,8 +356,8 @@ tab_icon_spacing = 4
tab_summary_spacing = 10
[search]
+max_editor_width = 400
match_background = "$state.highlighted_line"
-background = "$surface.1"
results_status = { extends = "$text.0", size = 18 }
tab_icon_width = 14
tab_icon_spacing = 4
@@ -388,7 +391,6 @@ extends = "$text.1"
padding = 6
[search.editor]
-max_width = 400
background = "$surface.0"
corner_radius = 6
padding = { left = 13, right = 13, top = 3, bottom = 3 }
@@ -21,6 +21,7 @@ pub use lsp;
use project::Project;
pub use project::{self, fs};
use project_panel::ProjectPanel;
+use search::SearchBar;
use std::{path::PathBuf, sync::Arc};
pub use workspace;
use workspace::{AppState, Settings, Workspace, WorkspaceParams};
@@ -104,6 +105,17 @@ pub fn build_workspace(
app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>,
) -> Workspace {
+ cx.subscribe(&cx.handle(), |_, _, event, cx| {
+ let workspace::Event::PaneAdded(pane) = event;
+ pane.update(cx, |pane, cx| {
+ pane.toolbar().update(cx, |toolbar, cx| {
+ let search_bar = cx.add_view(|cx| SearchBar::new(cx));
+ toolbar.add_right_item(search_bar, cx);
+ })
+ });
+ })
+ .detach();
+
let workspace_params = WorkspaceParams {
project,
client: app_state.client.clone(),