use aho_corasick::AhoCorasick; use editor::{Editor, EditorSettings}; use gpui::{ action, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, View, ViewContext, ViewHandle, }; use postage::watch; use std::sync::Arc; use workspace::{ItemViewHandle, Settings, Toolbar, Workspace}; action!(Deploy); action!(Cancel); pub fn init(cx: &mut MutableAppContext) { cx.add_bindings([ Binding::new("cmd-f", Deploy, Some("Editor && mode == full")), Binding::new("escape", Cancel, Some("FindBar")), ]); cx.add_action(FindBar::deploy); cx.add_action(FindBar::cancel); } struct FindBar { settings: watch::Receiver, query_editor: ViewHandle, active_editor: Option>, } impl Entity for FindBar { type Event = (); } impl View for FindBar { fn ui_name() -> &'static str { "FindBar" } fn on_focus(&mut self, cx: &mut ViewContext) { cx.focus(&self.query_editor); } fn render(&mut self, _: &mut RenderContext) -> ElementBox { ChildView::new(&self.query_editor) .contained() .with_style(self.settings.borrow().theme.selector.input_editor.container) .boxed() } } 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)); } fn on_query_editor_event( &mut self, _: ViewHandle, _: &editor::Event, cx: &mut ViewContext, ) { if let Some(editor) = &self.active_editor { let search = self.query_editor.read(cx).text(cx); if search.is_empty() { return; } let search = AhoCorasick::new_auto_configured(&[search]); editor.update(cx, |editor, cx| { let buffer = editor.buffer().read(cx).snapshot(cx); let mut ranges = search .stream_find_iter(buffer.bytes_in_range(0..buffer.len())) .map(|mat| { let mat = mat.unwrap(); mat.start()..mat.end() }) .peekable(); if ranges.peek().is_some() { editor.select_ranges(ranges, None, cx); } }); } } }