use anyhow::Result; use cursive::Cursive; use cursive::Printer; use cursive::Rect; use cursive::View; use cursive::XY; use cursive::direction::Direction; use cursive::event::Callback; use cursive::event::Event; use cursive::event::EventResult; use cursive::event::Key; use cursive::view::Nameable; use cursive::view::Selector; use cursive::view::SizeConstraint; use cursive::views::NamedView; use cursive::views::ResizedView; use crate::main_view::MainView; pub fn get_bindings() -> Bindings { Bindings(vec![ Binding { chars: ["quit", "q"].iter().map(ToString::to_string).collect(), callback: Callback::from_fn(|siv: &mut Cursive| { trace!("Callback called: q"); let continue_running = siv.call_on_name(crate::main_view::MAIN_VIEW_NAME, |mv: &mut MainView| { if mv.tabs().tab_order().len() == 1 { false } else { if let Some(key) = mv.tabs().active_tab().cloned() { debug!("Removing tab: {}", key); if let Err(e) = mv.tabs_mut().remove_tab(&key) { error!("{:?}", e); // TODO do more than just logging } debug!("Remove tab"); } else { debug!("No tab to remove found."); } true } }) .unwrap_or(true); if !continue_running { debug!("Byebye"); siv.quit(); } }) }, Binding { chars: ["open", "o"].iter().map(ToString::to_string).collect(), callback: Callback::from_fn(MainView::add_notmuch_query_layer), } ]) } pub const BINDINGS_CALLER: &str = "BINDINGS_CALLER"; #[derive(Clone)] pub struct Bindings(Vec); impl Bindings { pub fn new(bs: Vec) -> Bindings { Bindings(bs) } pub fn caller(&self) -> BindingCaller { BindingCaller::new(self.clone()) } } #[derive(Clone)] pub struct Binding { chars: Vec, callback: Callback, } impl Binding { pub fn for_events(chars: Vec, callback: Callback) -> Binding { Binding { chars, callback } } } pub struct BindingCaller { configuration: Bindings, state: Vec } impl BindingCaller { pub fn new(configuration: Bindings) -> Self { BindingCaller { configuration, state: Vec::new() } } pub fn process(&mut self, chr: char) { debug!("Char = {}", chr); self.state.push(chr); } pub fn finalize(&self) -> Option { self.configuration .0 .iter() .find(|binding| { trace!("chars {:?} == state {:?}", binding.chars, self.state); let state_str = self.state.iter().collect::(); binding.chars.iter().any(|state| *state == state_str) }) .map(|binding| { trace!("Binding found"); binding.callback.clone() }) } } impl View for BindingCaller { fn draw(&self, printer: &Printer) { trace!("Drawing with offset = {:?}", printer.offset); trace!("Drawing with output_size = {:?}", printer.output_size); trace!("Drawing with size = {:?}", printer.size); { let line = "-".repeat(printer.output_size.x); let position = XY { x: printer.offset.x, y: printer.output_size.y - 3, }; printer.print(position, &line) } { let line = format!(":{}", self.state.iter().collect::()); let position = XY { x: printer.offset.x, y: printer.output_size.y - 2, }; printer.print(position, &line) } } fn on_event(&mut self, e: Event) -> EventResult { match e { Event::Key(Key::Enter) => EventResult::Consumed(self.finalize()), Event::Char(chr) => { self.process(chr); EventResult::Consumed(None) }, _ => unimplemented!() } } }