diff --git a/README.md b/README.md index 9709bf4c34..359ec880a6 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ use rustyline::error::ReadlineError; use rustyline::Editor; fn main() { - let mut rl = Editor::new(); + let mut rl = Editor::<()>::new(); if let Err(_) = rl.load_history("history.txt") { println!("No previous history."); } diff --git a/examples/example.rs b/examples/example.rs index 4e553cd75f..134e1e25c8 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -16,7 +16,7 @@ static PROMPT: &'static str = ">> "; fn main() { let c = FilenameCompleter::new(); let mut rl = Editor::new().history_ignore_space(true); - rl.set_completer(Some(&c)); + rl.set_completer(Some(c)); if let Err(_) = rl.load_history("history.txt") { println!("No previous history."); } diff --git a/src/completion.rs b/src/completion.rs index 9a5aa39672..2359316744 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -23,6 +23,42 @@ pub trait Completer { } } +impl Completer for () { + fn complete(&self, _line: &str, _pos: usize) -> Result<(usize, Vec)> { + Ok((0, Vec::new())) + } + fn update(&self, _line: &mut LineBuffer, _start: usize, _elected: &str) { + unreachable!() + } +} + +impl<'c, C: ?Sized + Completer> Completer for &'c C { + fn complete(&self, line: &str, pos: usize) -> Result<(usize, Vec)> { + (**self).complete(line, pos) + } + fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) { + (**self).update(line, start, elected) + } +} +macro_rules! box_completer { + ($($id: ident)*) => { + $( + impl Completer for $id { + fn complete(&self, line: &str, pos: usize) -> Result<(usize, Vec)> { + (**self).complete(line, pos) + } + fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) { + (**self).update(line, start, elected) + } + } + )* + } +} + +use std::sync::Arc; +use std::rc::Rc; +box_completer! { Box Rc Arc } + pub struct FilenameCompleter { break_chars: BTreeSet, } diff --git a/src/lib.rs b/src/lib.rs index f52e2771dc..03a0bd9b8c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ //! Usage //! //! ``` -//! let mut rl = rustyline::Editor::new(); +//! let mut rl = rustyline::Editor::<()>::new(); //! let readline = rl.readline(">> "); //! match readline { //! Ok(line) => println!("Line: {:?}",line), @@ -888,18 +888,18 @@ fn readline_direct() -> Result { } /// Line editor -pub struct Editor<'completer> { +pub struct Editor { unsupported_term: bool, stdin_isatty: bool, stdout_isatty: bool, // cols: usize, // Number of columns in terminal history: History, - completer: Option<&'completer Completer>, + completer: Option, kill_ring: KillRing, } -impl<'completer> Editor<'completer> { - pub fn new() -> Editor<'completer> { +impl Editor { + pub fn new() -> Editor { // TODO check what is done in rl_initialize() // if the number of columns is stored here, we need a SIGWINCH handler... let editor = Editor { @@ -916,32 +916,12 @@ impl<'completer> Editor<'completer> { editor } - /// This method will read a line from STDIN and will display a `prompt` - #[cfg_attr(feature="clippy", allow(if_not_else))] - pub fn readline(&mut self, prompt: &str) -> Result { - if self.unsupported_term { - // Write prompt and flush it to stdout - let mut stdout = io::stdout(); - try!(write_and_flush(&mut stdout, prompt.as_bytes())); - - readline_direct() - } else if !self.stdin_isatty { - // Not a tty: read from file / pipe. - readline_direct() - } else { - readline_raw(prompt, - &mut self.history, - self.completer, - &mut self.kill_ring) - } - } - - pub fn history_ignore_space(mut self, yes: bool) -> Editor<'completer> { + pub fn history_ignore_space(mut self, yes: bool) -> Editor { self.history.ignore_space(yes); self } - pub fn history_ignore_dups(mut self, yes: bool) -> Editor<'completer> { + pub fn history_ignore_dups(mut self, yes: bool) -> Editor { self.history.ignore_dups(yes); self } @@ -970,20 +950,42 @@ impl<'completer> Editor<'completer> { pub fn get_history(&mut self) -> &mut History { &mut self.history } +} + +impl Editor { + /// This method will read a line from STDIN and will display a `prompt` + #[cfg_attr(feature="clippy", allow(if_not_else))] + pub fn readline(&mut self, prompt: &str) -> Result { + if self.unsupported_term { + // Write prompt and flush it to stdout + let mut stdout = io::stdout(); + try!(write_and_flush(&mut stdout, prompt.as_bytes())); + + readline_direct() + } else if !self.stdin_isatty { + // Not a tty: read from file / pipe. + readline_direct() + } else { + readline_raw(prompt, + &mut self.history, + self.completer.as_ref().map(|c| c as &Completer), + &mut self.kill_ring) + } + } /// Register a callback function to be called for tab-completion. - pub fn set_completer(&mut self, completer: Option<&'completer Completer>) { + pub fn set_completer(&mut self, completer: Option) { self.completer = completer; } } -impl<'completer> Default for Editor<'completer> { - fn default() -> Editor<'completer> { +impl Default for Editor { + fn default() -> Editor { Editor::new() } } -impl<'completer> fmt::Debug for Editor<'completer> { +impl fmt::Debug for Editor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("State") .field("unsupported_term", &self.unsupported_term)