fozzie/
lib.rs

1#![feature(test)]
2#[macro_use]
3extern crate clap;
4extern crate terminal_size;
5extern crate test;
6
7pub mod bonus;
8pub mod choices;
9pub mod choice;
10pub mod color;
11pub mod config;
12pub mod cursor;
13pub mod matcher;
14pub mod matrix;
15pub mod scorer;
16pub mod search;
17pub mod terminal;
18
19use choice::Choice;
20use choices::Choices;
21use config::Config;
22use search::Search;
23use std::error::Error;
24use std::io::{self, Read};
25use terminal::Terminal;
26use termion::event::Key;
27use rayon::prelude::*;
28
29pub struct App {}
30
31impl App {
32    pub fn run() -> Result<i32, Box<dyn Error>> {
33        let config = Config::new();
34        let mut exit_code = 0;
35
36        let mut terminal = Terminal::new()?;
37        let stdin = io::stdin();
38        let mut stdin_lock = stdin.lock();
39
40        let mut buffer = String::new();
41
42       if termion::is_tty(&stdin_lock) {
43           clap::Error::with_description(
44               "No input given", clap::ErrorKind::MissingRequiredArgument
45           ).exit();
46        }
47
48        stdin_lock.read_to_string(&mut buffer)?;
49        let parsed_choices: Vec<Choice> =
50            buffer.
51            par_lines().
52            map(|choice| Choice::new(choice, &config)).
53            collect();
54
55        let mut search = Search::new(config.prompt);
56        let mut choices = Choices::new(config.lines, &parsed_choices, config.show_scores);
57
58        if config.benchmark {
59            let query = config.query.unwrap().chars().collect::<Vec<char>>();
60            for _ in 0..100 {
61                choices.filter(&query);
62            }
63        } else {
64            choices.initial_draw(&mut terminal);
65            match config.query {
66                Some(query) => {
67                    terminal.print(&search.set_query(&query));
68                    terminal.print(&choices.filter(&search.query));
69                }
70                None => terminal.print(&search.draw())
71            }
72
73            for c in terminal.keys()? {
74                match c.unwrap() {
75                    Key::Alt(c) => match c as u8 {
76                        b'b' => {
77                            terminal.print(&search.left_word());
78                            terminal.print(&choices.filter(&search.query));
79                        },
80                        b'f' => {
81                            terminal.print(&search.right_word());
82                            terminal.print(&choices.filter(&search.query));
83                        },
84                        127 => {
85                            terminal.print(&search.backspace_word());
86                            terminal.print(&choices.filter(&search.query));
87                        },
88                        100 => {
89                            terminal.print(&search.delete_word());
90                            terminal.print(&choices.filter(&search.query));
91                        },
92                        _ => {}
93                    },
94                    Key::Char('\n') => {
95                        choices.select(&mut terminal);
96                        break;
97                    }
98                    Key::Char('\t') => {
99                        terminal.print(&search.set_query(choices.current_match().searchable));
100                        terminal.print(&choices.filter(&search.query));
101                    }
102                    Key::Char(c) => {
103                        terminal.print(&search.keypress(c));
104                        terminal.print(&choices.filter(&search.query));
105                    }
106                    Key::Ctrl('u') => terminal.print(&search.clear()),
107                    Key::Up => terminal.print(&choices.previous()),
108                    Key::Down => terminal.print(&choices.next()),
109                    Key::Esc | Key::Ctrl('c') => {
110                        exit_code = 1;
111                        terminal.print(&choices.cancel());
112                        break;
113                    }
114                    Key::Left => {
115                        if let Some(text) = search.left() {
116                            terminal.print(text);
117                        }
118                    }
119                    Key::Right => {
120                        if let Some(text) = search.right() {
121                            terminal.print(text);
122                        }
123                    }
124                    Key::Backspace => {
125                        if let Some(text) = search.backspace() {
126                            terminal.print(&text);
127                            terminal.print(&choices.filter(&search.query));
128                        }
129                    }
130                    Key::Ctrl('d') => {
131                        if let Some(text) = search.delete() {
132                            terminal.print(&text);
133                            terminal.print(&choices.filter(&search.query));
134                        }
135                    }
136                    _ => {}
137                }
138            }
139        }
140
141        Ok(exit_code)
142    }
143}