Commit 595158ef authored by MovingtoMars's avatar MovingtoMars
Browse files

Merge branch 'iamcodemaker-keymap'

parents 2de56539 befc8d76
target
Cargo.lock
history
# vim swap files
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
use std::io::{self, Stdout, stdout, stdin};
use std::io::{self, Stdout, stdout, stdin, Write};
use termion::input::TermRead;
use termion::raw::{IntoRawMode, RawTerminal};
use super::*;
use keymap;
/// The default for `Context.word_fn`.
pub fn get_buffer_words(buf: &Buffer) -> Vec<(usize, usize)> {
......@@ -62,24 +63,31 @@ impl Context {
mut handler: &mut EventHandler<RawTerminal<Stdout>>)
-> io::Result<String> {
let res = {
let stdin = stdin();
let stdout = stdout().into_raw_mode().unwrap();
let mut ed = try!(Editor::new(stdout, prompt.into(), self));
for c in stdin.keys() {
if try!(ed.handle_key(c.unwrap(), handler)) {
break;
}
}
Ok(ed.into())
let ed = try!(Editor::new(stdout, prompt.into(), self));
Self::handle_keys(keymap::Emacs::new(ed), handler)
};
self.revert_all_history();
res
}
fn handle_keys<'a, T, W: Write, M: KeyMap<'a, W, T>>(
mut keymap: M,
mut handler: &mut EventHandler<W>)
-> io::Result<String>
where String: From<M>
{
let stdin = stdin();
for c in stdin.keys() {
if try!(keymap.handle_key(c.unwrap(), handler)) {
break;
}
}
Ok(keymap.into())
}
pub fn revert_all_history(&mut self) {
for buf in &mut self.history.buffers {
buf.revert();
......
use std::io::{self, Write};
use termion::{self, clear, cursor};
use termion::event::Key;
use unicode_width::*;
use Context;
......@@ -150,77 +149,15 @@ impl<'a, W: Write> Editor<'a, W> {
self.cursor
}
pub fn handle_key(&mut self, key: Key, handler: &mut EventHandler<W>) -> io::Result<bool> {
let mut done = false;
send_event!(handler, self, BeforeKey, key);
match key {
Key::Char('\n') => {
try!(self.print_current_buffer(true));
try!(self.out.write(b"\r\n"));
done = true;
}
Key::Char('\t') => try!(self.complete(handler)),
Key::Char(c) => try!(self.insert_after_cursor(c)),
Key::Alt(c) => try!(self.handle_alt_key(c)),
Key::Ctrl(c) => try!(self.handle_ctrl_key(c)),
Key::Left => try!(self.move_cursor_left(1)),
Key::Right => try!(self.move_cursor_right(1)),
Key::Up => try!(self.move_up()),
Key::Down => try!(self.move_down()),
Key::Home => try!(self.move_cursor_to_start_of_line()),
Key::End => try!(self.move_cursor_to_end_of_line()),
Key::Backspace => try!(self.delete_before_cursor()),
Key::Delete => try!(self.delete_after_cursor()),
Key::Null => {}
_ => {}
}
match key {
Key::Char('\t') => {}
_ => self.show_completions_hint = false,
}
send_event!(handler, self, AfterKey, key);
try!(self.out.flush());
Ok(done)
}
fn handle_ctrl_key(&mut self, c: char) -> io::Result<()> {
match c {
'l' => self.clear(),
'a' => self.move_cursor_to_start_of_line(),
'e' => self.move_cursor_to_end_of_line(),
'b' => self.move_cursor_left(1),
'f' => self.move_cursor_right(1),
'd' => self.delete_after_cursor(),
'p' => self.move_up(),
'n' => self.move_down(),
'u' => self.delete_all_before_cursor(),
'k' => self.delete_all_after_cursor(),
'w' => self.delete_word_before_cursor(true),
'x' => {
try!(self.undo());
Ok(())
}
_ => Ok(()),
}
pub fn handle_newline(&mut self) -> io::Result<()> {
try!(self.print_current_buffer(true));
try!(self.out.write(b"\r\n"));
self.show_completions_hint = false;
Ok(())
}
fn handle_alt_key(&mut self, c: char) -> io::Result<()> {
match c {
'<' => self.move_to_start_of_history(),
'>' => self.move_to_end_of_history(),
'\x7F' => self.delete_word_before_cursor(true),
'r' => {
try!(self.revert());
Ok(())
}
_ => Ok(()),
}
pub fn flush(&mut self) -> io::Result<()> {
self.out.flush()
}
/// Attempts to undo an action on the current buffer.
......@@ -275,7 +212,11 @@ impl<'a, W: Write> Editor<'a, W> {
Ok(())
}
fn complete(&mut self, handler: &mut EventHandler<W>) -> io::Result<()> {
pub fn skip_completions_hint(&mut self) {
self.show_completions_hint = false;
}
pub fn complete(&mut self, handler: &mut EventHandler<W>) -> io::Result<()> {
send_event!(handler, self, BeforeComplete);
let (word, completions) = {
......@@ -630,7 +571,6 @@ impl<'a, W: Write> From<Editor<'a, W>> for String {
#[cfg(test)]
mod tests {
use super::*;
use termion::event::Key;
use Context;
macro_rules! simulate_keys {
......@@ -659,22 +599,6 @@ mod tests {
assert_eq!(String::from(ed), "delete all of this");
}
#[test]
fn enter_is_done() {
let mut context = Context::new();
let out = Vec::new();
let mut ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
ed.insert_str_after_cursor("done").unwrap();
assert_eq!(ed.cursor, 4);
assert!(simulate_keys!(ed, [
Key::Char('\n'),
]));
assert_eq!(ed.cursor, 4);
assert_eq!(String::from(ed), "done");
}
#[test]
fn move_cursor_left() {
let mut context = Context::new();
......@@ -683,11 +607,10 @@ mod tests {
ed.insert_str_after_cursor("let").unwrap();
assert_eq!(ed.cursor, 3);
simulate_keys!(ed, [
Key::Left,
Key::Char('f'),
]);
ed.move_cursor_left(1).unwrap();
assert_eq!(ed.cursor, 2);
ed.insert_after_cursor('f').unwrap();
assert_eq!(ed.cursor, 3);
assert_eq!(String::from(ed), "left");
}
......@@ -700,12 +623,8 @@ mod tests {
ed.insert_str_after_cursor("right").unwrap();
assert_eq!(ed.cursor, 5);
simulate_keys!(ed, [
Key::Left,
Key::Left,
Key::Right,
]);
ed.move_cursor_left(2).unwrap();
ed.move_cursor_right(1).unwrap();
assert_eq!(ed.cursor, 4);
}
}
use std::io::{self, Write};
use termion::event::Key;
use KeyMap;
use Editor;
pub struct Emacs<'a, W: Write> {
ed: Editor<'a, W>,
}
impl<'a, W: Write> Emacs<'a, W> {
pub fn new(ed: Editor<'a, W>) -> Self {
Emacs {
ed: ed,
}
}
fn handle_ctrl_key(&mut self, c: char) -> 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),
'x' => {
try!(self.ed.undo());
Ok(())
}
_ => Ok(()),
}
}
fn handle_alt_key(&mut self, c: char) -> 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),
'r' => {
try!(self.ed.revert());
Ok(())
}
_ => Ok(()),
}
}
}
impl<'a, W: Write> KeyMap<'a, W, Emacs<'a, W>> for Emacs<'a, W> {
fn handle_key_core(&mut self, key: Key) -> io::Result<()> {
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::Null => Ok(()),
_ => Ok(()),
}
}
fn editor(&mut self) -> &mut Editor<'a, W> {
&mut self.ed
}
}
impl<'a, W: Write> From<Emacs<'a, W>> for String {
fn from(emacs: Emacs<'a, W>) -> String {
emacs.ed.into()
}
}
#[cfg(test)]
mod tests {
use super::*;
use termion::event::Key;
use Context;
use Editor;
use KeyMap;
use std::io::Write;
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
where I: Iterator<Item=&'b Key>
{
for k in keys {
if keymap.handle_key(*k, &mut |_| {}).unwrap() {
return true;
}
}
false
}
#[test]
fn enter_is_done() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
let mut map = Emacs::new(ed);
map.ed.insert_str_after_cursor("done").unwrap();
assert_eq!(map.ed.cursor(), 4);
assert!(simulate_keys!(map, [
Key::Char('\n'),
]));
assert_eq!(map.ed.cursor(), 4);
assert_eq!(String::from(map), "done");
}
#[test]
fn move_cursor_left() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
let mut map = Emacs::new(ed);
map.editor().insert_str_after_cursor("let").unwrap();
assert_eq!(map.ed.cursor(), 3);
simulate_keys!(map, [
Key::Left,
Key::Char('f'),
]);
assert_eq!(map.ed.cursor(), 3);
assert_eq!(String::from(map), "left");
}
#[test]
fn cursor_movement() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
let mut map = Emacs::new(ed);
map.ed.insert_str_after_cursor("right").unwrap();
assert_eq!(map.ed.cursor(), 5);
simulate_keys!(map, [
Key::Left,
Key::Left,
Key::Right,
]);
assert_eq!(map.ed.cursor(), 4);
}
}
use std::io::{self, Write};
use termion::event::Key;
use Editor;
use event::*;
pub trait KeyMap<'a, W: Write, T> : From<T> {
fn handle_key_core(&mut self, key: Key) -> io::Result<()>;
fn editor(&mut self) -> &mut Editor<'a, W>;
fn handle_key(&mut self, key: Key, handler: &mut EventHandler<W>) -> io::Result<bool> {
let mut done = false;
handler(Event::new(self.editor(), EventKind::BeforeKey(key)));
match key {
Key::Char('\t') => try!(self.editor().complete(handler)),
Key::Char('\n') => {
try!(self.editor().handle_newline());
done = true;
}
_ => {
try!(self.handle_key_core(key));
self.editor().skip_completions_hint();
}
};
handler(Event::new(self.editor(), EventKind::AfterKey(key)));
try!(self.editor().flush());
Ok(done)
}
}
pub mod emacs;
pub use emacs::Emacs;
......@@ -19,6 +19,9 @@ pub use buffer::*;
mod history;
pub use history::*;
mod keymap;
pub use keymap::*;
mod util;
#[cfg(test)]
......
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