comments.rs 5.17 KB
Newer Older
MovingtoMars's avatar
MovingtoMars committed
1 2
extern crate liner;
extern crate termion;
3
extern crate regex;
MovingtoMars's avatar
MovingtoMars committed
4 5

use std::mem::replace;
6
use std::env::{args, current_dir};
7
use std::io;
MovingtoMars's avatar
MovingtoMars committed
8 9

use liner::{Context, CursorPosition, Event, EventKind, FilenameCompleter};
10 11 12
use termion::color;
use regex::Regex;

Liam Naddell's avatar
Liam Naddell committed
13
// This prints out the text back onto the screen
Sag0Sag0's avatar
Sag0Sag0 committed
14
fn highlight_dodo(s: &str) -> String {
15 16
    let reg_exp = Regex::new("(?P<k>dodo)").unwrap();
    let format = format!("{}$k{}", color::Fg(color::Red), color::Fg(color::Reset));
Sag0Sag0's avatar
Sag0Sag0 committed
17
    reg_exp.replace_all(s, format.as_str()).to_string()
18
}
MovingtoMars's avatar
MovingtoMars committed
19

20
fn main() {
MovingtoMars's avatar
MovingtoMars committed
21 22
    let mut con = Context::new();

23 24 25 26 27 28 29 30 31 32
    let history_file = match args().nth(1) {
        Some(file_name) => {
            println!("History file: {}", file_name);
            file_name
        }
        None => {
            eprintln!("No history file provided. Ending example early.");
            return;
        }
    };
33

34
    con.history.set_file_name_and_load_history(history_file).unwrap();
Sag0Sag0's avatar
Sag0Sag0 committed
35

MovingtoMars's avatar
MovingtoMars committed
36
    loop {
Liam Naddell's avatar
Liam Naddell committed
37 38
        // Reads the line, the first arg is the prompt, the second arg is a function called on every bit of text leaving liner, and the third is called on every key press
        // Basically highlight_dodo(read_line()), where on every keypress, the lambda is called
Sag0Sag0's avatar
Sag0Sag0 committed
39
        let res = con.read_line("[prompt]$ ",
Sag0Sag0's avatar
Sag0Sag0 committed
40
                                Some(Box::new(highlight_dodo)),
41
                                &mut |Event { editor, kind }| {
Liam Naddell's avatar
Liam Naddell committed
42

43 44 45 46 47
            if let EventKind::BeforeComplete = kind {
                let (_, pos) = editor.get_words_and_cursor_position();

                // Figure out of we are completing a command (the first word) or a filename.
                let filename = match pos {
Liam Naddell's avatar
Liam Naddell committed
48 49
                    // If we are inside of a word(i is the index inside of the text, and if that
                    // position is over zero, we return true
50
                    CursorPosition::InWord(i) => i > 0,
Liam Naddell's avatar
Liam Naddell committed
51 52
                    // If we are in a space like this `cat | cart` or cat |
                    // checks if there is a word to our left(indicated by there being Some value)
53
                    CursorPosition::InSpace(Some(_), _) => true,
Liam Naddell's avatar
Liam Naddell committed
54
                    // Checks if there is no word to our left(indicated by there being None value)
55
                    CursorPosition::InSpace(None, _) => false,
Liam Naddell's avatar
Liam Naddell committed
56 57
                    // If we are on the left edge of a word, and the position of the cursor is
                    // greater than or equal to 1, return true
58
                    CursorPosition::OnWordLeftEdge(i) => i >= 1,
Liam Naddell's avatar
Liam Naddell committed
59
                    // If we are on the right edge of the word
60 61 62
                    CursorPosition::OnWordRightEdge(i) => i >= 1,
                };

Liam Naddell's avatar
Liam Naddell committed
63 64 65 66 67
                // If we are not in a word with pos over zero, or in a space with text beforehand,
                // or on the left edge of a word with pos >= to 1, or on the Right edge of a word
                // under the same condition, then
                // This condition is only false under the predicate that we are in a space with no
                // word to the left
68 69 70 71
                if filename {
                    let completer = FilenameCompleter::new(Some(current_dir().unwrap()));
                    replace(&mut editor.context().completer, Some(Box::new(completer)));
                } else {
Liam Naddell's avatar
Liam Naddell committed
72
                    // Delete the completer
73 74 75 76 77
                    replace(&mut editor.context().completer, None);
                }
            }
        });

Liam Naddell's avatar
Liam Naddell committed
78
        // We are out of the lambda, and res is the result from read_line which is an Into<String>
79 80 81 82 83 84 85 86 87 88 89 90 91 92
        match res {
            Ok(res) => {
                match res.as_str() {
                    "emacs" => {
                        con.key_bindings = liner::KeyBindings::Emacs;
                        println!("emacs mode");
                    }
                    "vi" => {
                        con.key_bindings = liner::KeyBindings::Vi;
                        println!("vi mode");
                    }
                    "exit" | "" => {
                        println!("exiting...");
                        break;
MovingtoMars's avatar
MovingtoMars committed
93
                    }
Liam Naddell's avatar
Liam Naddell committed
94
                    // If all else fails, do nothing
95
                    _ => {}
MovingtoMars's avatar
MovingtoMars committed
96 97
                }

98
                // If we typed nothing, don't continue down to pushing to history
99 100 101 102 103 104
                if res.is_empty() {
                    break;
                }

                con.history.push(res.into()).unwrap();
            }
Liam Naddell's avatar
Liam Naddell committed
105 106
            // If there was an error, get what type it was(remember, we still are in the match{}
            // from waaay above)
107 108 109 110 111 112 113 114 115
            Err(e) => {
                match e.kind() {
                    // ctrl-c pressed
                    io::ErrorKind::Interrupted => {}
                    // ctrl-d pressed
                    io::ErrorKind::UnexpectedEof => {
                        println!("exiting...");
                        break;
                    }
Michael Aaron Murphy's avatar
Michael Aaron Murphy committed
116 117
                    _ => {
                        // Ensure that all writes to the history file
Liam Naddell's avatar
Liam Naddell committed
118
                        // are written before exiting due to error.
Michael Aaron Murphy's avatar
Michael Aaron Murphy committed
119 120
                        panic!("error: {:?}", e)
                    },
121 122
                }
            }
MovingtoMars's avatar
MovingtoMars committed
123
        }
124

Liam Naddell's avatar
Liam Naddell committed
125
    // End loop
MovingtoMars's avatar
MovingtoMars committed
126
    }
Michael Aaron Murphy's avatar
Michael Aaron Murphy committed
127 128

    // Ensure that all writes to the history file are written before exiting.
129
    con.history.commit_to_file();
Liam Naddell's avatar
Liam Naddell committed
130
}