Skip to content

Commit

Permalink
Handle Ctrl-Key events in EditView & some general, small improvements (
Browse files Browse the repository at this point in the history
…#739)

* EditView: Handle ctrl-key events ^U, ^K, ^A, ^E, ^B and ^F

These are respectively kill-to-front, kill-to-end, home, end, left and
right.

Signed-off-by: Christoph Heiss <[email protected]>

* EditView: Add method for retrieving current cursor position

This is useful in a variety of use cases, e.g. simply checking whether
it is legal to .remove() some characters or not.

Signed-off-by: Christoph Heiss <[email protected]>

* EditView: Do not panic on remove when trying to remove more than available

We can simply clamp it to current content length.

Signed-off-by: Christoph Heiss <[email protected]>

* EditView: Add test for ctrl-key events

Signed-off-by: Christoph Heiss <[email protected]>

---------

Signed-off-by: Christoph Heiss <[email protected]>
  • Loading branch information
christoph-heiss authored Aug 17, 2023
1 parent ea88010 commit 75bc082
Showing 1 changed file with 55 additions and 6 deletions.
61 changes: 55 additions & 6 deletions cursive-core/src/views/edit_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,11 @@ impl EditView {
self
}

/// Returns the currest cursor position.
pub fn get_cursor(&self) -> usize {
self.cursor
}

/// Sets the cursor position.
pub fn set_cursor(&mut self, cursor: usize) {
self.cursor = cursor;
Expand Down Expand Up @@ -425,7 +430,7 @@ impl EditView {
/// You should run this callback with a `&mut Cursive`.
pub fn remove(&mut self, len: usize) -> Callback {
let start = self.cursor;
let end = self.cursor + len;
let end = self.cursor + len.min(self.content.len() - self.cursor);
for _ in Rc::make_mut(&mut self.content).drain(start..end) {}

self.keep_cursor_in_view();
Expand Down Expand Up @@ -601,14 +606,25 @@ impl View for EditView {
Event::Char(ch) => {
return EventResult::Consumed(Some(self.insert(ch)));
}
// TODO: handle ctrl-key?
Event::Key(Key::Home) => self.set_cursor(0),
Event::Key(Key::End) => {
Event::CtrlChar('u') => {
// kill-to-front
let content = self.content[self.cursor..].to_owned();
let callback = self.set_content(content);
self.set_cursor(0);
return EventResult::Consumed(Some(callback));
}
Event::CtrlChar('k') => {
// kill-to-end
let content = self.content[..self.cursor].to_owned();
return EventResult::Consumed(Some(self.set_content(content)));
}
Event::Key(Key::Home) | Event::CtrlChar('a') => self.set_cursor(0),
Event::Key(Key::End) | Event::CtrlChar('e') => {
// When possible, NLL to the rescue!
let len = self.content.len();
self.set_cursor(len);
}
Event::Key(Key::Left) if self.cursor > 0 => {
Event::Key(Key::Left) | Event::CtrlChar('b') if self.cursor > 0 => {
let len = self.content[..self.cursor]
.graphemes(true)
.last()
Expand All @@ -617,7 +633,7 @@ impl View for EditView {
let cursor = self.cursor - len;
self.set_cursor(cursor);
}
Event::Key(Key::Right) if self.cursor < self.content.len() => {
Event::Key(Key::Right) | Event::CtrlChar('f') if self.cursor < self.content.len() => {
let len = self.content[self.cursor..]
.graphemes(true)
.next()
Expand Down Expand Up @@ -750,3 +766,36 @@ crate::var_recipe!("EditView.with_content", |config, context| {

Ok(result)
});

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn ctrl_key_events() {
let mut view = EditView::new().content("foobarbaz");
view.set_cursor(0);

view.on_event(Event::CtrlChar('f'));
assert_eq!(view.get_cursor(), 1);

view.on_event(Event::CtrlChar('b'));
assert_eq!(view.get_cursor(), 0);

view.on_event(Event::CtrlChar('e'));
assert_eq!(view.get_cursor(), view.get_content().len());

view.on_event(Event::CtrlChar('a'));
assert_eq!(view.get_cursor(), 0);

view.set_cursor(3);
view.on_event(Event::CtrlChar('u'));
assert_eq!(view.get_cursor(), 0);
assert_eq!(*view.get_content(), "barbaz");

view.set_cursor(3);
view.on_event(Event::CtrlChar('k'));
assert_eq!(view.get_cursor(), 3);
assert_eq!(*view.get_content(), "bar");
}
}

0 comments on commit 75bc082

Please sign in to comment.