use std::borrow::Cow::{self, Borrowed, Owned}; use rustyline::completion::FilenameCompleter; use rustyline::error::ReadlineError; use rustyline::highlight::{Highlighter, MatchingBracketHighlighter}; use rustyline::hint::HistoryHinter; use rustyline::validate::MatchingBracketValidator; use rustyline::{Cmd, CompletionType, Config, EditMode, Editor, KeyEvent}; use rustyline::{Completer, Helper, Hinter, Validator}; #[derive(Helper, Completer, Hinter, Validator)] struct MyHelper { #[rustyline(Completer)] completer: FilenameCompleter, highlighter: MatchingBracketHighlighter, #[rustyline(Validator)] validator: MatchingBracketValidator, #[rustyline(Hinter)] hinter: HistoryHinter, colored_prompt: String, } impl Highlighter for MyHelper { fn highlight_prompt<'b, 's: 'b, 'p: 'b>( &'s self, prompt: &'p str, default: bool, ) -> Cow<'b, str> { if default { Borrowed(&self.colored_prompt) } else { Borrowed(prompt) } } fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { Owned("\x1b[1m".to_owned() + hint + "\x1b[m") } fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> { self.highlighter.highlight(line, pos) } fn highlight_char(&self, line: &str, pos: usize, forced: bool) -> bool { self.highlighter.highlight_char(line, pos, forced) } } // To debug rustyline: // RUST_LOG=rustyline=debug cargo run --example example 2> debug.log fn main() -> rustyline::Result<()> { env_logger::init(); let config = Config::builder() .history_ignore_space(true) .completion_type(CompletionType::List) .edit_mode(EditMode::Emacs) .build(); let h = MyHelper { completer: FilenameCompleter::new(), highlighter: MatchingBracketHighlighter::new(), hinter: HistoryHinter::new(), colored_prompt: "".to_owned(), validator: MatchingBracketValidator::new(), }; let mut rl = Editor::with_config(config)?; rl.set_helper(Some(h)); rl.bind_sequence(KeyEvent::alt('n'), Cmd::HistorySearchForward); rl.bind_sequence(KeyEvent::alt('p'), Cmd::HistorySearchBackward); if rl.load_history("history.txt").is_err() { println!("No previous history."); } let mut count = 1; loop { let p = format!("{count}> "); rl.helper_mut().expect("No helper").colored_prompt = format!("\x1b[1;32m{p}\x1b[0m"); let readline = rl.readline(&p); match readline { Ok(line) => { rl.add_history_entry(line.as_str())?; println!("Line: {line}"); } Err(ReadlineError::Interrupted) => { println!("Interrupted"); break; } Err(ReadlineError::Eof) => { println!("Encountered Eof"); break; } Err(err) => { println!("Error: {err:?}"); break; } } count += 1; } rl.append_history("history.txt") }