diff --git a/src/views/edit_view.rs b/src/views/edit_view.rs index 044bc0e..9afa540 100644 --- a/src/views/edit_view.rs +++ b/src/views/edit_view.rs @@ -3,6 +3,7 @@ use {Cursive, Printer, With}; use direction::Direction; use event::{Callback, Event, EventResult, Key}; +use std::cell::RefCell; use std::rc::Rc; use theme::{ColorStyle, Effect}; @@ -74,7 +75,7 @@ pub struct EditView { /// Callback when the content is modified. /// - /// Will be called with the current content and the cursor position + /// Will be called with the current content and the cursor position. on_edit: Option>, /// Callback when is pressed. @@ -136,25 +137,118 @@ impl EditView { self.enabled = true; } + /// Sets a mutable callback to be called whenever the content is modified. + /// + /// `callback` will be called with the view + /// content and the current cursor position. + /// + /// *Warning*: this callback cannot be called recursively. If you somehow + /// trigger this callback again in the given closure, it will be ignored. + /// + /// If you don't need a mutable closure but want the possibility of + /// recursive calls, see [`set_on_edit`](#method.set_on_edit). + pub fn set_on_edit_mut(&mut self, callback: F) + where F: FnMut(&mut Cursive, &str, usize) + 'static + { + let callback = RefCell::new(callback); + // Here's the weird trick: if we're already borrowed, + // just ignored the callback. + self.set_on_edit(move |s, text, cursor| { + if let Ok(mut f) = callback.try_borrow_mut() { + // Beeeaaah that's ugly. + // Why do we need to manually dereference here? + (&mut *f)(s, text, cursor); + } + }); + } + /// Sets a callback to be called whenever the content is modified. /// /// `callback` will be called with the view /// content and the current cursor position. - pub fn on_edit(mut self, callback: F) -> Self + /// + /// This callback can safely trigger itself recursively if needed + /// (for instance if you call `on_event` on this view from the callback). + /// + /// If you need a mutable closure and don't care about the recursive + /// aspect, see [`set_on_edit_mut`](#method.set_on_edit_mut). + pub fn set_on_edit(&mut self, callback: F) where F: Fn(&mut Cursive, &str, usize) + 'static { self.on_edit = Some(Rc::new(callback)); - self + } + + /// Sets a mutable callback to be called whenever the content is modified. + /// + /// Chainable variant. See [`set_on_edit_mut`](#method.set_on_edit_mut). + pub fn on_edit_mut(self, callback: F) -> Self + where F: FnMut(&mut Cursive, &str, usize) + 'static + { + self.with(|v| v.set_on_edit_mut(callback)) + } + + /// Sets a callback to be called whenever the content is modified. + /// + /// Chainable variant. See [`set_on_edit`](#method.set_on_edit). + pub fn on_edit(self, callback: F) -> Self + where F: Fn(&mut Cursive, &str, usize) + 'static + { + self.with(|v| v.set_on_edit(callback)) + } + + /// Sets a mutable callback to be called when `` is pressed. + /// + /// `callback` will be given the content of the view. + /// + /// *Warning*: this callback cannot be called recursively. If you somehow + /// trigger this callback again in the given closure, it will be ignored. + /// + /// If you don't need a mutable closure but want the possibility of + /// recursive calls, see [`set_on_submit`](#method.set_on_submit). + pub fn set_on_submit_mut(&mut self, callback: F) + where F: FnMut(&mut Cursive, &str) + 'static + { + // TODO: don't duplicate all those methods. + // Instead, have some generic function immutify() + // or something that wraps a FnMut closure. + let callback = RefCell::new(callback); + self.set_on_submit(move |s, text| if let Ok(mut f) = + callback.try_borrow_mut() { + (&mut *f)(s, text); + }); } /// Sets a callback to be called when `` is pressed. /// /// `callback` will be given the content of the view. - pub fn on_submit(mut self, callback: F) -> Self + /// + /// This callback can safely trigger itself recursively if needed + /// (for instance if you call `on_event` on this view from the callback). + /// + /// If you need a mutable closure and don't care about the recursive + /// aspect, see [`set_on_submit_mut`](#method.set_on_submit_mut). + pub fn set_on_submit(&mut self, callback: F) where F: Fn(&mut Cursive, &str) + 'static { self.on_submit = Some(Rc::new(callback)); - self + } + + /// Sets a mutable callback to be called when `` is pressed. + /// + /// Chainable variant. + pub fn on_submit_mut(self, callback: F) -> Self + where F: FnMut(&mut Cursive, &str) + 'static + { + self.with(|v| v.set_on_submit_mut(callback)) + } + + /// Sets a callback to be called when `` is pressed. + /// + /// Chainable variant. + pub fn on_submit(self, callback: F) -> Self + where F: Fn(&mut Cursive, &str) + 'static + { + self.with(|v| v.set_on_submit(callback)) } /// Enable or disable this view. @@ -239,9 +333,10 @@ impl EditView { // Look at the content before the cursor (we will print its tail). // From the end, count the length until we reach `available`. // Then sum the byte lengths. - let suffix_length = - simple_suffix(&self.content[self.offset..self.cursor], - available).length; + let suffix_length = simple_suffix(&self.content[self.offset.. + self.cursor], + available) + .length; self.offset = self.cursor - suffix_length; // Make sure the cursor is in view assert!(self.cursor >= self.offset); @@ -250,8 +345,8 @@ impl EditView { // If we have too much space if self.content[self.offset..].width() < self.last_length { - let suffix_length = simple_suffix(&self.content, - self.last_length - 1).length; + let suffix_length = + simple_suffix(&self.content, self.last_length - 1).length; self.offset = self.content.len() - suffix_length; } } @@ -393,9 +488,7 @@ impl View for EditView { Event::Key(Key::Enter) if self.on_submit.is_some() => { let cb = self.on_submit.clone().unwrap(); let content = self.content.clone(); - return EventResult::with_cb(move |s| { - cb(s, &content); - }); + return EventResult::with_cb(move |s| { cb(s, &content); }); } _ => return EventResult::Ignored, } @@ -404,13 +497,11 @@ impl View for EditView { let cb = self.on_edit.clone().map(|cb| { - // Get a new Rc on it + // Get a new Rc on the content let content = self.content.clone(); let cursor = self.cursor; - Callback::from_fn(move |s| { - cb(s, &content, cursor); - }) + Callback::from_fn(move |s| { cb(s, &content, cursor); }) }); EventResult::Consumed(cb) }