Skip to content

Commit

Permalink
Parametrize Editor by the Completer type
Browse files Browse the repository at this point in the history
This allows the `Editor` to implement `Sync` as long as it contains a completer which implement `Sync`. It lets the `Editor` take ownership of the completer.
  • Loading branch information
Marwes committed Jul 16, 2016
1 parent 85d5d84 commit 83664d9
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
}
Expand Down
2 changes: 1 addition & 1 deletion examples/example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
}
Expand Down
36 changes: 36 additions & 0 deletions src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,42 @@ pub trait Completer {
}
}

impl Completer for () {
fn complete(&self, _line: &str, _pos: usize) -> Result<(usize, Vec<String>)> {
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<String>)> {
(**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<C: ?Sized + Completer> Completer for $id<C> {
fn complete(&self, line: &str, pos: usize) -> Result<(usize, Vec<String>)> {
(**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<char>,
}
Expand Down
64 changes: 33 additions & 31 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -888,18 +888,18 @@ fn readline_direct() -> Result<String> {
}

/// Line editor
pub struct Editor<'completer> {
pub struct Editor<C> {
unsupported_term: bool,
stdin_isatty: bool,
stdout_isatty: bool,
// cols: usize, // Number of columns in terminal
history: History,
completer: Option<&'completer Completer>,
completer: Option<C>,
kill_ring: KillRing,
}

impl<'completer> Editor<'completer> {
pub fn new() -> Editor<'completer> {
impl<C> Editor<C> {
pub fn new() -> Editor<C> {
// TODO check what is done in rl_initialize()
// if the number of columns is stored here, we need a SIGWINCH handler...
let editor = Editor {
Expand All @@ -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<String> {
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<C> {
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<C> {
self.history.ignore_dups(yes);
self
}
Expand Down Expand Up @@ -970,20 +950,42 @@ impl<'completer> Editor<'completer> {
pub fn get_history(&mut self) -> &mut History {
&mut self.history
}
}

impl<C: Completer> Editor<C> {
/// 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<String> {
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<C>) {
self.completer = completer;
}
}

impl<'completer> Default for Editor<'completer> {
fn default() -> Editor<'completer> {
impl<C> Default for Editor<C> {
fn default() -> Editor<C> {
Editor::new()
}
}

impl<'completer> fmt::Debug for Editor<'completer> {
impl<C> fmt::Debug for Editor<C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("State")
.field("unsupported_term", &self.unsupported_term)
Expand Down

0 comments on commit 83664d9

Please sign in to comment.