Commit 367de8bc authored by Michael Aaron Murphy's avatar Michael Aaron Murphy

Merge branch 'keymap-no-own-editor' into 'master'

Keymap should not own the editor

See merge request redox-os/liner!16
parents df0f67e5 43d81445
Pipeline #4332 passed with stage
in 2 minutes and 1 second
......@@ -107,10 +107,10 @@ impl Context {
) -> io::Result<String> {
let res = {
let mut stdout = stdout().into_raw_mode()?;
let ed = Editor::new_with_init_buffer(stdout, prompt, f, self, buffer)?;
let mut ed = Editor::new_with_init_buffer(stdout, prompt, f, self, buffer)?;
match self.key_bindings {
KeyBindings::Emacs => Self::handle_keys(keymap::Emacs::new(ed), handler),
KeyBindings::Vi => Self::handle_keys(keymap::Vi::new(ed), handler),
KeyBindings::Emacs => Self::handle_keys(keymap::Emacs::new(), ed, handler),
KeyBindings::Vi => Self::handle_keys(keymap::Vi::new(), ed, handler),
}
};
......@@ -118,22 +118,19 @@ impl Context {
res
}
fn handle_keys<'a, T, W: Write, M: KeyMap<'a, W, T>, C: Completer<W>>(
fn handle_keys<'a, W: Write, M: KeyMap, C: Completer<W>>(
mut keymap: M,
mut ed: Editor<'a, W>,
handler: &mut C,
) -> io::Result<String>
where
String: From<M>,
{
let stdin = stdin();
let stdin = stdin.lock();
for c in stdin.keys() {
if keymap.handle_key(c.unwrap(), handler)? {
) -> io::Result<String> {
keymap.init(&mut ed);
for c in stdin().keys() {
if keymap.handle_key(c.unwrap(), &mut ed, handler)? {
break;
}
}
Ok(keymap.into())
Ok(ed.into())
}
pub fn revert_all_history(&mut self) {
......
......@@ -12,84 +12,80 @@ use KeyMap;
/// let mut context = Context::new();
/// context.key_bindings = KeyBindings::Emacs;
/// ```
pub struct Emacs<'a, W: Write> {
ed: Editor<'a, W>,
#[derive(Default)]
pub struct Emacs {
last_arg_fetch_index: Option<usize>,
}
impl<'a, W: Write> Emacs<'a, W> {
pub fn new(ed: Editor<'a, W>) -> Self {
Emacs {
ed,
last_arg_fetch_index: None,
}
impl Emacs {
pub fn new() -> Self {
Self::default()
}
fn handle_ctrl_key(&mut self, c: char) -> io::Result<()> {
fn handle_ctrl_key<'a, W: Write>(&mut self, c: char, ed: &mut Editor<'a, W>) -> io::Result<()> {
match c {
'l' => self.ed.clear(),
'a' => self.ed.move_cursor_to_start_of_line(),
'e' => self.ed.move_cursor_to_end_of_line(),
'b' => self.ed.move_cursor_left(1),
'f' => self.ed.move_cursor_right(1),
'd' => self.ed.delete_after_cursor(),
'p' => self.ed.move_up(),
'n' => self.ed.move_down(),
'u' => self.ed.delete_all_before_cursor(),
'k' => self.ed.delete_all_after_cursor(),
'w' => self.ed.delete_word_before_cursor(true),
'l' => ed.clear(),
'a' => ed.move_cursor_to_start_of_line(),
'e' => ed.move_cursor_to_end_of_line(),
'b' => ed.move_cursor_left(1),
'f' => ed.move_cursor_right(1),
'd' => ed.delete_after_cursor(),
'p' => ed.move_up(),
'n' => ed.move_down(),
'u' => ed.delete_all_before_cursor(),
'k' => ed.delete_all_after_cursor(),
'w' => ed.delete_word_before_cursor(true),
'x' => {
self.ed.undo()?;
ed.undo()?;
Ok(())
}
_ => Ok(()),
}
}
fn handle_alt_key(&mut self, c: char) -> io::Result<()> {
fn handle_alt_key<'a, W: Write>(&mut self, c: char, ed: &mut Editor<'a, W>) -> io::Result<()> {
match c {
'<' => self.ed.move_to_start_of_history(),
'>' => self.ed.move_to_end_of_history(),
'\x7F' => self.ed.delete_word_before_cursor(true),
'f' => emacs_move_word(&mut self.ed, EmacsMoveDir::Right),
'b' => emacs_move_word(&mut self.ed, EmacsMoveDir::Left),
'<' => ed.move_to_start_of_history(),
'>' => ed.move_to_end_of_history(),
'\x7F' => ed.delete_word_before_cursor(true),
'f' => emacs_move_word(ed, EmacsMoveDir::Right),
'b' => emacs_move_word(ed, EmacsMoveDir::Left),
'r' => {
self.ed.revert()?;
ed.revert()?;
Ok(())
}
'.' => self.handle_last_arg_fetch(),
'.' => self.handle_last_arg_fetch(ed),
_ => Ok(()),
}
}
fn handle_last_arg_fetch(&mut self) -> io::Result<()> {
fn handle_last_arg_fetch<'a, W: Write>(&mut self, ed: &mut Editor<'a, W>) -> io::Result<()> {
// Empty history means no last arg to fetch.
if self.ed.context().history.len() == 0 {
if ed.context().history.len() == 0 {
return Ok(());
}
let history_index = match self.last_arg_fetch_index {
Some(0) => return Ok(()),
Some(x) => x - 1,
None => self
.ed
None => ed
.current_history_location()
.unwrap_or(self.ed.context().history.len() - 1),
.unwrap_or(ed.context().history.len() - 1),
};
// If did a last arg fetch just before this, we need to delete it so it can be replaced by
// this last arg fetch.
if self.last_arg_fetch_index.is_some() {
let buffer_len = self.ed.current_buffer().num_chars();
if let Some(last_arg_len) = self.ed.current_buffer().last_arg().map(|x| x.len()) {
self.ed.delete_until(buffer_len - last_arg_len)?;
let buffer_len = ed.current_buffer().num_chars();
if let Some(last_arg_len) = ed.current_buffer().last_arg().map(|x| x.len()) {
ed.delete_until(buffer_len - last_arg_len)?;
}
}
// Actually insert it
let buf = self.ed.context().history[history_index].clone();
let buf = ed.context().history[history_index].clone();
if let Some(last_arg) = buf.last_arg() {
self.ed.insert_chars_after_cursor(last_arg)?;
ed.insert_chars_after_cursor(last_arg)?;
}
// Edit the index in case the user does a last arg fetch again.
......@@ -99,43 +95,33 @@ impl<'a, W: Write> Emacs<'a, W> {
}
}
impl<'a, W: Write> KeyMap<'a, W, Emacs<'a, W>> for Emacs<'a, W> {
fn handle_key_core(&mut self, key: Key) -> io::Result<()> {
impl KeyMap for Emacs {
fn handle_key_core<'a, W: Write>(
&mut self,
key: Key,
ed: &mut Editor<'a, W>,
) -> io::Result<()> {
match key {
Key::Alt('.') => {}
_ => self.last_arg_fetch_index = None,
}
match key {
Key::Char(c) => self.ed.insert_after_cursor(c),
Key::Alt(c) => self.handle_alt_key(c),
Key::Ctrl(c) => self.handle_ctrl_key(c),
Key::Left => self.ed.move_cursor_left(1),
Key::Right => self.ed.move_cursor_right(1),
Key::Up => self.ed.move_up(),
Key::Down => self.ed.move_down(),
Key::Home => self.ed.move_cursor_to_start_of_line(),
Key::End => self.ed.move_cursor_to_end_of_line(),
Key::Backspace => self.ed.delete_before_cursor(),
Key::Delete => self.ed.delete_after_cursor(),
Key::Char(c) => ed.insert_after_cursor(c),
Key::Alt(c) => self.handle_alt_key(c, ed),
Key::Ctrl(c) => self.handle_ctrl_key(c, ed),
Key::Left => ed.move_cursor_left(1),
Key::Right => ed.move_cursor_right(1),
Key::Up => ed.move_up(),
Key::Down => ed.move_down(),
Key::Home => ed.move_cursor_to_start_of_line(),
Key::End => ed.move_cursor_to_end_of_line(),
Key::Backspace => ed.delete_before_cursor(),
Key::Delete => ed.delete_after_cursor(),
Key::Null => Ok(()),
_ => Ok(()),
}
}
fn editor_mut(&mut self) -> &mut Editor<'a, W> {
&mut self.ed
}
fn editor(&self) -> &Editor<'a, W> {
&self.ed
}
}
impl<'a, W: Write> From<Emacs<'a, W>> for String {
fn from(emacs: Emacs<'a, W>) -> String {
emacs.ed.into()
}
}
#[derive(PartialEq, Clone, Copy)]
......@@ -192,18 +178,16 @@ mod tests {
use Editor;
use KeyMap;
macro_rules! simulate_keys {
($keymap:ident, $keys:expr) => {{
simulate_keys(&mut $keymap, $keys.into_iter())
}};
}
fn simulate_keys<'a, 'b, W: Write, T, M: KeyMap<'a, W, T>, I>(keymap: &mut M, keys: I) -> bool
fn simulate_keys<'a, 'b, W: Write, M: KeyMap, I>(
keymap: &mut M,
ed: &mut Editor<'a, W>,
keys: I,
) -> bool
where
I: Iterator<Item = &'b Key>,
I: IntoIterator<Item = &'b Key>,
{
for k in keys {
if keymap.handle_key(*k, &mut EmptyCompleter).unwrap() {
if keymap.handle_key(*k, ed, &mut EmptyCompleter).unwrap() {
return true;
}
}
......@@ -223,66 +207,65 @@ mod tests {
fn enter_is_done() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = Emacs::new(ed);
map.ed.insert_str_after_cursor("done").unwrap();
assert_eq!(map.ed.cursor(), 4);
let mut ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = Emacs::new();
ed.insert_str_after_cursor("done").unwrap();
assert_eq!(ed.cursor(), 4);
assert!(simulate_keys!(map, [Key::Char('\n')]));
assert!(simulate_keys(&mut map, &mut ed, [Key::Char('\n')].iter()));
assert_eq!(map.ed.cursor(), 4);
assert_eq!(String::from(map), "done");
assert_eq!(ed.cursor(), 4);
assert_eq!(String::from(ed), "done");
}
#[test]
fn move_cursor_left() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = Emacs::new(ed);
map.editor_mut().insert_str_after_cursor("let").unwrap();
assert_eq!(map.ed.cursor(), 3);
let mut ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = Emacs::new();
ed.insert_str_after_cursor("let").unwrap();
assert_eq!(ed.cursor(), 3);
simulate_keys!(map, [Key::Left, Key::Char('f')]);
simulate_keys(&mut map, &mut ed, [Key::Left, Key::Char('f')].iter());
assert_eq!(map.ed.cursor(), 3);
assert_eq!(String::from(map), "left");
assert_eq!(ed.cursor(), 3);
assert_eq!(String::from(ed), "left");
}
#[test]
fn move_word() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = Emacs::new(ed);
map.editor_mut()
.insert_str_after_cursor("abc def ghi")
.unwrap();
assert_eq!(map.ed.cursor(), 11);
simulate_keys!(map, [Key::Alt('b')]);
let mut ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = Emacs::new();
ed.insert_str_after_cursor("abc def ghi").unwrap();
assert_eq!(ed.cursor(), 11);
simulate_keys(&mut map, &mut ed, [Key::Alt('b')].iter());
// Move to `g`
assert_eq!(map.ed.cursor(), 8);
assert_eq!(ed.cursor(), 8);
simulate_keys!(map, [Key::Alt('b'), Key::Alt('f')]);
simulate_keys(&mut map, &mut ed, [Key::Alt('b'), Key::Alt('f')].iter());
// Move to the char after `f`
assert_eq!(map.ed.cursor(), 7);
assert_eq!(ed.cursor(), 7);
}
#[test]
fn cursor_movement() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = Emacs::new(ed);
map.ed.insert_str_after_cursor("right").unwrap();
assert_eq!(map.ed.cursor(), 5);
let mut ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = Emacs::new();
ed.insert_str_after_cursor("right").unwrap();
assert_eq!(ed.cursor(), 5);
simulate_keys!(map, [Key::Left, Key::Left, Key::Right]);
simulate_keys(&mut map, &mut ed, [Key::Left, Key::Left, Key::Right].iter());
assert_eq!(map.ed.cursor(), 4);
assert_eq!(ed.cursor(), 4);
}
#[test]
......@@ -290,12 +273,12 @@ mod tests {
fn ctrl_h() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = Emacs::new(ed);
map.ed.insert_str_after_cursor("not empty").unwrap();
let mut ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = Emacs::new();
ed.insert_str_after_cursor("not empty").unwrap();
let res = map.handle_key(Key::Ctrl('h'), &mut EmptyCompleter);
let res = map.handle_key(Key::Ctrl('h'), &mut ed, &mut EmptyCompleter);
assert_eq!(res.is_ok(), true);
assert_eq!(map.ed.current_buffer().to_string(), "not empt".to_string());
assert_eq!(ed.current_buffer().to_string(), "not empt".to_string());
}
}
......@@ -4,17 +4,26 @@ use std::io::{self, ErrorKind, Write};
use termion::event::Key;
use Editor;
pub trait KeyMap<'a, W: Write, T>: From<T> {
fn handle_key_core(&mut self, key: Key) -> io::Result<()>;
fn editor(&self) -> &Editor<'a, W>;
fn editor_mut(&mut self) -> &mut Editor<'a, W>;
fn handle_key<C: Completer<W>>(&mut self, mut key: Key, handler: &mut C) -> io::Result<bool> {
pub trait KeyMap: Default {
fn handle_key_core<'a, W: Write>(
&mut self,
key: Key,
editor: &mut Editor<'a, W>,
) -> io::Result<()>;
fn init<'a, W: Write>(&mut self, _editor: &mut Editor<'a, W>) {}
fn handle_key<'a, W: Write, C: Completer<W>>(
&mut self,
mut key: Key,
editor: &mut Editor<'a, W>,
handler: &mut C,
) -> io::Result<bool> {
let mut done = false;
handler.on_event(Event::new(self.editor_mut(), EventKind::BeforeKey(key)));
handler.on_event(Event::new(editor, EventKind::BeforeKey(key)));
let is_empty = self.editor().current_buffer().is_empty();
let is_empty = editor.current_buffer().is_empty();
if key == Key::Ctrl('h') {
// XXX: Might need to change this when remappable keybindings are added.
......@@ -23,42 +32,42 @@ pub trait KeyMap<'a, W: Write, T>: From<T> {
match key {
Key::Ctrl('c') => {
self.editor_mut().handle_newline()?;
editor.handle_newline()?;
return Err(io::Error::new(ErrorKind::Interrupted, "ctrl-c"));
}
// if the current buffer is empty, treat ctrl-d as eof
Key::Ctrl('d') if is_empty => {
self.editor_mut().handle_newline()?;
editor.handle_newline()?;
return Err(io::Error::new(ErrorKind::UnexpectedEof, "ctrl-d"));
}
Key::Char('\t') => self.editor_mut().complete(handler)?,
Key::Char('\t') => editor.complete(handler)?,
Key::Char('\n') => {
done = self.editor_mut().handle_newline()?;
done = editor.handle_newline()?;
}
Key::Ctrl('f') if self.editor().is_currently_showing_autosuggestion() => {
self.editor_mut().accept_autosuggestion()?;
Key::Ctrl('f') if editor.is_currently_showing_autosuggestion() => {
editor.accept_autosuggestion()?;
}
Key::Ctrl('r') => {
self.editor_mut().search(false)?;
editor.search(false)?;
}
Key::Ctrl('s') => {
self.editor_mut().search(true)?;
editor.search(true)?;
}
Key::Right
if self.editor().is_currently_showing_autosuggestion()
&& self.editor().cursor_is_at_end_of_line() =>
if editor.is_currently_showing_autosuggestion()
&& editor.cursor_is_at_end_of_line() =>
{
self.editor_mut().accept_autosuggestion()?;
editor.accept_autosuggestion()?;
}
_ => {
self.handle_key_core(key)?;
self.editor_mut().skip_completions_hint();
self.handle_key_core(key, editor)?;
editor.skip_completions_hint();
}
};
handler.on_event(Event::new(self.editor_mut(), EventKind::AfterKey(key)));
handler.on_event(Event::new(editor, EventKind::AfterKey(key)));
self.editor_mut().flush()?;
editor.flush()?;
Ok(done)
}
......@@ -77,28 +86,17 @@ mod tests {
use termion::event::Key::*;
use Context;
struct TestKeyMap<'a, W: Write> {
ed: Editor<'a, W>,
}
impl<'a, W: Write> TestKeyMap<'a, W> {
pub fn new(ed: Editor<'a, W>) -> Self {
TestKeyMap { ed: ed }
}
}
#[derive(Default)]
struct TestKeyMap;
impl<'a, W: Write> KeyMap<'a, W, TestKeyMap<'a, W>> for TestKeyMap<'a, W> {
fn handle_key_core(&mut self, _: Key) -> io::Result<()> {
impl KeyMap for TestKeyMap {
fn handle_key_core<'a, W: Write>(
&mut self,
_: Key,
_: &mut Editor<'a, W>,
) -> io::Result<()> {
Ok(())
}
fn editor_mut(&mut self) -> &mut Editor<'a, W> {
&mut self.ed
}
fn editor(&self) -> &Editor<'a, W> {
&self.ed
}
}
struct EmptyCompleter;
......@@ -114,10 +112,10 @@ mod tests {
fn ctrl_d_empty() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = TestKeyMap::new(ed);
let mut ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = TestKeyMap;
let res = map.handle_key(Ctrl('d'), &mut EmptyCompleter);
let res = map.handle_key(Ctrl('d'), &mut ed, &mut EmptyCompleter);
assert_eq!(res.is_err(), true);
assert_eq!(res.err().unwrap().kind(), ErrorKind::UnexpectedEof);
}
......@@ -127,11 +125,11 @@ mod tests {
fn ctrl_d_non_empty() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = TestKeyMap::new(ed);
map.ed.insert_str_after_cursor("not empty").unwrap();
let mut ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = TestKeyMap;
ed.insert_str_after_cursor("not empty").unwrap();
let res = map.handle_key(Ctrl('d'), &mut EmptyCompleter);
let res = map.handle_key(Ctrl('d'), &mut ed, &mut EmptyCompleter);
assert_eq!(res.is_ok(), true);
}
......@@ -140,10 +138,10 @@ mod tests {
fn ctrl_c() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = TestKeyMap::new(ed);
let mut ed = Editor::new(out, "prompt".to_owned(), None, &mut context).unwrap();
let mut map = TestKeyMap;
let res = map.handle_key(Ctrl('c'), &mut EmptyCompleter);
let res = map.handle_key(Ctrl('c'), &mut ed, &mut EmptyCompleter);
assert_eq!(res.is_err(), true);
assert_eq!(res.err().unwrap().kind(), ErrorKind::Interrupted);
}
......
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment