1 extern crate liner;
2 extern crate regex;
3 extern crate termion;
4
5 use std::env::{args, current_dir};
6 use std::io;
7 use std::mem::replace;
8
9 use liner::{Completer, Context, CursorPosition, Event, EventKind, FilenameCompleter};
10 use regex::Regex;
11 use termion::color;
12
highlight_dodo(s: &str) -> String13 fn highlight_dodo(s: &str) -> String {
14 let reg_exp = Regex::new("(?P<k>dodo)").unwrap();
15 let format = format!("{}$k{}", color::Fg(color::Red), color::Fg(color::Reset));
16 reg_exp.replace_all(s, format.as_str()).to_string()
17 }
18
19 struct NoCommentCompleter {
20 inner: Option<FilenameCompleter>,
21 }
22
23 impl Completer for NoCommentCompleter {
completions(&mut self, start: &str) -> Vec<String>24 fn completions(&mut self, start: &str) -> Vec<String> {
25 if let Some(inner) = &mut self.inner {
26 inner.completions(start)
27 } else {
28 Vec::new()
29 }
30 }
31
on_event<W: std::io::Write>(&mut self, event: Event<W>)32 fn on_event<W: std::io::Write>(&mut self, event: Event<W>) {
33 if let EventKind::BeforeComplete = event.kind {
34 let (_, pos) = event.editor.get_words_and_cursor_position();
35
36 // Figure out of we are completing a command (the first word) or a filename.
37 let filename = match pos {
38 CursorPosition::InWord(i) => i > 0,
39 CursorPosition::InSpace(Some(_), _) => true,
40 CursorPosition::InSpace(None, _) => false,
41 CursorPosition::OnWordLeftEdge(i) => i >= 1,
42 CursorPosition::OnWordRightEdge(i) => i >= 1,
43 };
44
45 if filename {
46 let completer = FilenameCompleter::new(Some(current_dir().unwrap()));
47 replace(&mut self.inner, Some(completer));
48 } else {
49 replace(&mut self.inner, None);
50 }
51 }
52 }
53 }
54
main()55 fn main() {
56 let mut con = Context::new();
57 let mut completer = NoCommentCompleter { inner: None };
58
59 let history_file = match args().nth(1) {
60 Some(file_name) => {
61 println!("History file: {}", file_name);
62 file_name
63 }
64 None => {
65 eprintln!("No history file provided. Ending example early.");
66 return;
67 }
68 };
69
70 con.history
71 .set_file_name_and_load_history(history_file)
72 .unwrap();
73
74 loop {
75 let res = con.read_line("[prompt]$ ", Some(Box::new(highlight_dodo)), &mut completer);
76
77 match res {
78 Ok(res) => {
79 match res.as_str() {
80 "emacs" => {
81 con.key_bindings = liner::KeyBindings::Emacs;
82 println!("emacs mode");
83 }
84 "vi" => {
85 con.key_bindings = liner::KeyBindings::Vi;
86 println!("vi mode");
87 }
88 "exit" | "" => {
89 println!("exiting...");
90 break;
91 }
92 _ => {}
93 }
94
95 if res.is_empty() {
96 break;
97 }
98
99 con.history.push(res.into()).unwrap();
100 }
101 Err(e) => {
102 match e.kind() {
103 // ctrl-c pressed
104 io::ErrorKind::Interrupted => {}
105 // ctrl-d pressed
106 io::ErrorKind::UnexpectedEof => {
107 println!("exiting...");
108 break;
109 }
110 _ => {
111 // Ensure that all writes to the history file
112 // are written before exiting.
113 panic!("error: {:?}", e)
114 }
115 }
116 }
117 }
118 }
119 // Ensure that all writes to the history file are written before exiting.
120 con.history.commit_to_file();
121 }
122