1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
|
use log::{Level, LevelFilter, Metadata, Record, SetLoggerError};
use std::borrow::Cow::{self, Borrowed, Owned};
use rustyline::completion::{Completer, FilenameCompleter, Pair};
use rustyline::config::OutputStreamType;
use rustyline::error::ReadlineError;
use rustyline::highlight::{Highlighter, MatchingBracketHighlighter};
use rustyline::hint::Hinter;
use rustyline::{Cmd, CompletionType, Config, EditMode, Editor, Helper, KeyPress};
static COLORED_PROMPT: &'static str = "\x1b[1;32m>>\x1b[0m ";
static PROMPT: &'static str = ">> ";
struct MyHelper(FilenameCompleter, MatchingBracketHighlighter);
impl Completer for MyHelper {
type Candidate = Pair;
fn complete(&self, line: &str, pos: usize) -> Result<(usize, Vec<Pair>), ReadlineError> {
self.0.complete(line, pos)
}
}
impl Hinter for MyHelper {
fn hint(&self, line: &str, _pos: usize) -> Option<String> {
if line == "hello" {
Some(" World".to_owned())
} else {
None
}
}
}
impl Highlighter for MyHelper {
fn highlight_prompt<'p>(&self, prompt: &'p str) -> Cow<'p, str> {
if prompt == PROMPT {
Borrowed(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.1.highlight(line, pos)
}
fn highlight_char(&self, line: &str, pos: usize) -> bool {
self.1.highlight_char(line, pos)
}
}
impl Helper for MyHelper {}
fn main() {
init_logger().is_ok();
let config = Config::builder()
.history_ignore_space(true)
.completion_type(CompletionType::List)
.edit_mode(EditMode::Emacs)
.output_stream(OutputStreamType::Stdout)
.build();
let h = MyHelper(FilenameCompleter::new(), MatchingBracketHighlighter::new());
let mut rl = Editor::with_config(config);
rl.set_helper(Some(h));
rl.bind_sequence(KeyPress::Meta('N'), Cmd::HistorySearchForward);
rl.bind_sequence(KeyPress::Meta('P'), Cmd::HistorySearchBackward);
if rl.load_history("history.txt").is_err() {
println!("No previous history.");
}
loop {
let readline = rl.readline(PROMPT);
match readline {
Ok(line) => {
rl.add_history_entry(line.as_str());
println!("Line: {}", line);
}
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
break;
}
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break;
}
Err(err) => {
println!("Error: {:?}", err);
break;
}
}
}
rl.save_history("history.txt").unwrap();
}
static LOGGER: Logger = Logger;
struct Logger;
impl log::Log for Logger {
fn enabled(&self, metadata: &Metadata<'_>) -> bool {
metadata.level() <= Level::Debug
}
fn log(&self, record: &Record<'_>) {
if self.enabled(record.metadata()) {
eprintln!("{} - {}", record.level(), record.args());
}
}
fn flush(&self) {}
}
fn init_logger() -> Result<(), SetLoggerError> {
log::set_logger(&LOGGER)?;
log::set_max_level(LevelFilter::Info);
Ok(())
}
|