Add EditView::set_cursor

And fix a crash with `set_content` (it wasn't updating the cursor).
This commit is contained in:
Alexandre Bury 2016-09-01 11:10:12 -07:00
parent 67ba15045f
commit 0364f577b2

View File

@ -167,6 +167,7 @@ impl EditView {
/// Replace the entire content of the view with the given one. /// Replace the entire content of the view with the given one.
pub fn set_content(&mut self, content: &str) { pub fn set_content(&mut self, content: &str) {
self.offset = 0; self.offset = 0;
self.cursor = 0;
self.content = Rc::new(content.to_string()); self.content = Rc::new(content.to_string());
} }
@ -183,6 +184,13 @@ impl EditView {
self self
} }
/// Sets the cursor position.
pub fn set_cursor(&mut self, cursor: usize) {
self.cursor = cursor;
self.keep_cursor_in_view();
}
/// Insert `ch` at the current cursor position. /// Insert `ch` at the current cursor position.
pub fn insert(&mut self, ch: char) { pub fn insert(&mut self, ch: char) {
// `make_mut` applies copy-on-write // `make_mut` applies copy-on-write
@ -198,6 +206,44 @@ impl EditView {
let end = self.cursor + len; let end = self.cursor + len;
for _ in Rc::make_mut(&mut self.content).drain(start..end) {} for _ in Rc::make_mut(&mut self.content).drain(start..end) {}
} }
fn keep_cursor_in_view(&mut self) {
// keep cursor in [offset, offset+last_length] by changing offset
// so keep offset in [last_length-cursor,cursor]
// Also call this on resize,
// but right now it is an event like any other
if self.cursor < self.offset {
self.offset = self.cursor;
} else {
// So we're against the right wall.
// Let's find how much space will be taken by the selection
// (either a char, or _)
let c_len = self.content[self.cursor..]
.graphemes(true)
.map(|g| g.width())
.next()
.unwrap_or(1);
// Now, we have to fit self.content[..self.cursor]
// into self.last_length - c_len.
let available = self.last_length - c_len;
// 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_length(&self.content[self.offset..self.cursor],
available);
self.offset = self.cursor - suffix_length;
assert!(self.cursor >= self.offset);
}
// If we have too much space
if self.content[self.offset..].width() < self.last_length {
let suffix_length = simple_suffix_length(&self.content,
self.last_length - 1);
self.offset = self.content.len() - suffix_length;
}
}
} }
/// Returns a `&str` with `length` characters `*`. /// Returns a `&str` with `length` characters `*`.
@ -350,41 +396,7 @@ impl View for EditView {
_ => return EventResult::Ignored, _ => return EventResult::Ignored,
} }
// Keep cursor in [offset, offset+last_length] by changing offset self.keep_cursor_in_view();
// So keep offset in [last_length-cursor,cursor]
// Also call this on resize,
// but right now it is an event like any other
if self.cursor < self.offset {
self.offset = self.cursor;
} else {
// So we're against the right wall.
// Let's find how much space will be taken by the selection
// (either a char, or _)
let c_len = self.content[self.cursor..]
.graphemes(true)
.map(|g| g.width())
.next()
.unwrap_or(1);
// Now, we have to fit self.content[..self.cursor]
// into self.last_length - c_len.
let available = self.last_length - c_len;
// 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_length(&self.content[self.offset..self.cursor],
available);
self.offset = self.cursor - suffix_length;
assert!(self.cursor >= self.offset);
}
// If we have too much space
if self.content[self.offset..].width() < self.last_length {
let suffix_length = simple_suffix_length(&self.content,
self.last_length - 1);
self.offset = self.content.len() - suffix_length;
}
let cb = self.on_edit.clone().map(|cb| { let cb = self.on_edit.clone().map(|cb| {