ls_key/
terminal.rs

1pub mod parent_shell {
2    use::std::thread;
3    use xdotool;
4    use xdotool::keyboard;
5    use xdotool::option_vec;
6    use xdotool::optionvec::OptionVec;
7    use xdotool::command::options::KeyboardOption;
8
9    pub fn send_key<T: AsRef<str>>(key: T, delay: u32) {
10        keyboard::send_key(key.as_ref(), option_vec![
11            KeyboardOption::Delay(delay)
12        ]);
13    }
14
15    pub fn type_text<T: AsRef<str>>(text: T, delay: u32/*, options: Option<KeyboardOption>*/) -> std::process::Output {
16        if text.as_ref() == "BackSpace" {
17             keyboard::send_key("BackSpace".as_ref(), option_vec![
18                 KeyboardOption::Delay(delay)
19             ])
20        } else {
21            keyboard::type_text(text.as_ref(), option_vec![
22                KeyboardOption::Delay(delay)
23            ])
24        }
25    }
26
27    pub fn type_text_spawn(text: Vec<String>, delay: u32/*, options: Option<KeyboardOption>*/)  -> thread::JoinHandle<()> {
28        //let text = text.as_ref().to_string();
29	    let type_text = thread::spawn(move || {
30	       // Send loop
31	       // Send the message
32           let text_iter = text.iter();
33           let type_n_sleep = |text: String, delay: u32| {
34               let few_ms = std::time::Duration::from_millis(100);
35               std::thread::sleep(few_ms);
36               if text == format!(r#""BackSpace""#) {
37                   send_key("BackSpace", delay);
38               } else {
39                   type_text(text, delay);
40               }
41           };
42
43           text_iter.for_each(|x|
44               type_n_sleep(x.to_string(), delay)
45           );
46	    });
47        //super::parent_shell::type_text(r#""$(printf 'cd $HOME && fzf \n ')""#);
48
49	   type_text
50    }
51}
52pub mod input_n_display {
53    use termion::input::TermRead;
54    use termion::event::Key;
55    use termion::raw::{IntoRawMode, RawTerminal};
56    use termion::terminal_size;
57    use term_grid::{/*Grid,*/ GridOptions, Direction, /*Display,*/ Filling, Cell};
58    use std::io::{Read, Write, stdout, stdin, Stdout, StdoutLock};
59    use termion::async_stdin;
60    use termion::screen::AlternateScreen;
61    use std::thread;
62    use std::time::Duration;
63    pub use term_grid::{Grid, Display};
64
65    pub fn read() -> Result<Option<String>, std::io::Error> {
66        let stdout = stdout();
67        let mut stdout = stdout.lock();
68        let stdin = stdin();
69        let mut stdin = stdin.lock();
70
71        stdout.write_all(b":").unwrap();
72        stdout.flush().unwrap();
73
74        stdin.read_line()
75    }
76
77    // (columns/width, lines/height)
78    pub fn size() -> (u16, u16) {
79        terminal_size().unwrap()
80    }
81
82    pub fn alternate_screen() {
83        {
84            let mut screen: AlternateScreen<Stdout> = AlternateScreen::from(stdout());
85            write!(screen, "Writing to alternat(iv)e screen!").unwrap();
86            screen.flush().unwrap();
87        }
88        println!("Writing to main screen again.");
89    }
90
91    pub fn read_char_async() {
92        let stdout = stdout();
93        let mut stdout = stdout.lock().into_raw_mode().unwrap();
94        let mut stdin = async_stdin().bytes();
95
96        write!(stdout,
97               "{}{}",
98               termion::clear::All,
99               termion::cursor::Goto(1, 1))
100                .unwrap();
101
102        loop {
103            write!(stdout, "{}", termion::clear::CurrentLine).unwrap();
104
105            let b = stdin.next();
106            write!(stdout, "\r{:?}    <- This demonstrates the async read input char. Between each update a 100 ms. is waited, simply to demonstrate the async fashion. \n\r", b).unwrap();
107            if let Some(Ok(b'q')) = b {
108                break;
109            }
110
111            stdout.flush().unwrap();
112
113            thread::sleep(Duration::from_millis(50));
114            stdout.write_all(b"# ").unwrap();
115            stdout.flush().unwrap();
116            thread::sleep(Duration::from_millis(50));
117            stdout.write_all(b"\r #").unwrap();
118            write!(stdout, "{}", termion::cursor::Goto(1, 1)).unwrap();
119            stdout.flush().unwrap();
120        }
121    }
122
123    pub fn read_process_chars() -> Option<String> {
124        let mut input: Vec<char> = vec![];
125        let stdin = stdin();
126        let stdout = stdout();
127        let mut stdout = stdout.lock().into_raw_mode().unwrap();
128        let stdin = stdin.lock();
129        let mut result: Option<String> =  None;
130
131        write!(stdout, "{}{}\n\r", termion::clear::CurrentLine, termion::cursor::Goto(1, 1)).unwrap();
132        //write!(stdout,
133        //    "{}{}",
134        //   termion::clear::All,
135        //   termion::cursor::Goto(1, 1),
136        //).unwrap();
137        //stdout.flush().unwrap();
138
139        fn write(some_stuff: &[u8], stdout: &mut RawTerminal<StdoutLock>, input_string: String) {
140            //stdout.write_all(some_stuff).unwrap();
141            //stdout.flush().unwrap();
142            write!(
143                stdout,
144                "{}\n\r",std::str::from_utf8(&some_stuff).unwrap(),
145
146            ).unwrap();
147            //write!(stdout, "{}", termion::clear::CurrentLine).unwrap();
148            write!(stdout,
149                "{}{}{}{}", format!("{}", input_string.as_str()
150                ),
151               termion::clear::AfterCursor,
152               termion::cursor::Goto(1, 1),
153               termion::cursor::Hide,
154            ).unwrap();
155        }
156
157        for c in stdin.keys() {
158            match c.unwrap() {
159                Key::Char('q') => break,
160                Key::Char(c) => {
161                    match c {
162                        //' ' => {
163                        //    println!("$")
164                        //},
165                        //'v' => println!("{}im", c),
166                        _ => {
167                            input.push(c);
168                        }
169                    }
170                }
171                Key::Alt(c) => println!("^{}", c),
172                Key::Ctrl(c) => println!("*{}", c),
173                Key::Esc => println!("ESC"),
174                Key::Left => println!("←"),
175                Key::Right => println!("→"),
176                Key::Up => println!("↑"),
177                Key::Down => println!("↓"),
178                Key::Backspace => {
179                    if !input.pop().is_some() {
180                        write!(stdout, "{}{}", termion::cursor::Goto(0, 2), termion::clear::AfterCursor).unwrap();
181                    }
182                },
183                _ => {}
184            }
185            let input_string: String = input.iter().collect();
186            let _first = input.iter().nth(0);
187            if let Some(mut first) = _first {
188                let key: Result<usize, std::num::ParseIntError> = first.to_string().parse();
189                if key.is_ok() {
190                    first = &'r';
191                } else {
192                    if first != &'$' {
193                         first = &'f';
194                    }
195                }
196
197                match first {
198                    'f' => write(b"fuzzy-widdle mode detected...", &mut stdout, input_string.clone()),
199                    'r' => write(b"return file mode detected...", &mut stdout, input_string.clone()),
200                    '$' => write(b"command mode detected... ", &mut stdout, input_string.clone()),
201                    _ => write(b"invalid mode detected...", &mut stdout, input_string.clone()),
202                };
203            }
204
205            stdout.flush().unwrap();
206
207            if input.iter().last() == Some(&'\n') {
208                input.pop();
209                let input_string: String = input.iter().collect();
210                result = Some(input_string);
211                break
212            }
213        }
214
215        write!(stdout, "{}", termion::cursor::Show).unwrap();
216        result
217    }
218
219    pub fn read_char() {
220        let stdin = stdin();
221        let mut stdout = stdout().into_raw_mode().unwrap();
222
223        write!(stdout,
224               "{}{}q to exit. Type stuff, use alt, and so on.{}",
225               termion::clear::All,
226               termion::cursor::Goto(1, 1),
227               termion::cursor::Hide)
228                .unwrap();
229        stdout.flush().unwrap();
230
231        for c in stdin.keys() {
232            write!(stdout,
233                   "{}{}",
234                   termion::cursor::Goto(1, 1),
235                   termion::clear::CurrentLine)
236                    .unwrap();
237
238            match c.unwrap() {
239                Key::Char('q') => break,
240                Key::Char(c) => {
241                    match c {
242                        //' ' => {
243                        //    println!("$")
244                        //},
245                        //'v' => println!("{}im", c),
246                        _ => println!("{}", c),
247                    }
248                }
249                Key::Alt(c) => println!("^{}", c),
250                Key::Ctrl(c) => println!("*{}", c),
251                Key::Esc => println!("ESC"),
252                Key::Left => println!("←"),
253                Key::Right => println!("→"),
254                Key::Up => println!("↑"),
255                Key::Down => println!("↓"),
256                Key::Backspace => println!("×"),
257                _ => {}
258            }
259            stdout.flush().unwrap();
260        }
261
262        write!(stdout, "{}", termion::cursor::Show).unwrap();
263    }
264
265   // pub fn display(grid: Grid, width: usize) {
266   //     println!("{}", grid.fit_into_width(width))
267   //     //let grid = grid.fit_into_width(w));
268   //     //if let Some(g) = grid {
269   //     //    true
270   //     //} else {
271   //     //    false
272   //     //}
273   // }
274
275    pub fn grid(entries: Vec<String>) -> Option<(Grid, usize, usize)> {
276        let mut grid = Grid::new(GridOptions {
277                filling:     Filling::Spaces(3),
278                direction:   Direction::LeftToRight,
279        });
280
281        for s in &entries
282        {
283                grid.add(Cell::from(s.as_str()));
284        }
285
286        //let stdout = stdout();
287        //let mut stdout = stdout.lock();
288        //let stdin = stdin();
289        //let mut stdin = stdin.lock();
290
291        let res = terminal_size();
292        match res {
293          Ok(r) => {
294              let w = usize::from(r.0);
295              let h = usize::from(r.1);
296
297              Some((grid, w, h))
298          },
299          Err(_) => {
300              None
301          }
302        }
303    }
304
305    pub fn grid_display(entries: Vec<String>) /*Result<(Grid), Error>*/{
306        let mut grid = Grid::new(GridOptions {
307                filling:     Filling::Spaces(3),
308                direction:   Direction::LeftToRight,
309        });
310
311        for s in &entries
312        {
313                grid.add(Cell::from(s.as_str()));
314        }
315
316        let (w, _) = terminal_size()/*; match this     */.unwrap();
317        /*match (w, h) {
318            Ok((w, h)) => {
319                let w = usize::from(w);
320                let h = usize::from(h);
321                grid.fit_into_width(w)
322            },
323            Err(_) => {
324                None
325            }
326          }
327        */
328
329        let w = usize::from(w);
330
331        println!("{}", grid.fit_into_width(w).unwrap());
332    }
333}
334
335pub mod shell {
336    use cmd_lib::run_fun;
337
338    pub fn spawn(cmd: String, args: Vec<String>) {
339        std::process::Command::new(cmd)
340            .args(args)
341            .spawn()
342            .expect("failed to execute shell process.")
343            .wait()
344            .expect("unrecoverable failure to execute shell process.");
345    }
346
347    pub fn output(cmd: String, args: Vec<String>) -> Result<std::process::Output, std::io::Error> {
348        std::process::Command::new(cmd)
349            .args(args)
350            .output()
351    }
352
353    pub fn cmd(cmd: String) -> Result<String, std::io::Error> {
354        run_fun!("{}", cmd)
355    }
356}
357
358pub mod grid_display {
359    pub fn grid() {
360       use term_grid::{Grid, GridOptions, Direction, Filling, Cell};
361
362       let mut grid = Grid::new(GridOptions {
363               filling:     Filling::Spaces(7),
364               direction:   Direction::LeftToRight,
365       });
366
367       for s in &["one", "two", "three", "four", "five", "six", "seven",
368                  "eight", "nine", "ten", "eleven", "twelve"]
369       {
370               grid.add(Cell::from(*s));
371       }
372
373       println!("{}", grid.fit_into_width(50).unwrap());
374    }
375
376    pub fn grid_abnormal() {
377       use term_grid::{Grid, GridOptions, Direction, Filling, Cell};
378
379       let mut grid = Grid::new(GridOptions {
380               filling:     Filling::Spaces(4),
381               direction:   Direction::LeftToRight,
382       });
383
384       for s in &["one", "two"]
385       {
386               grid.add(Cell::from(*s));
387       }
388
389       println!("{}", grid.fit_into_width(24).unwrap());
390    }
391
392    pub fn grid_no_borrow() {
393       use term_grid::{Grid, GridOptions, Direction, Filling, Cell};
394
395       let mut grid = Grid::new(GridOptions {
396               filling:     Filling::Spaces(1),
397               direction:   Direction::LeftToRight,
398       });
399
400       for s in ["one".to_string(), "two".to_string(), "three".to_string(), "four".to_string(), "five".to_string(), "six".to_string(), "seven".to_string(),
401                  "eight".to_string(), "nine".to_string(), "ten".to_string(), "eleven".to_string(), "twelve".to_string()].iter()
402       {
403               grid.add(Cell::from(s.clone()));
404       }
405
406       println!("{}", grid.fit_into_width(24).unwrap());
407    }
408}
409
410#[cfg(test)]
411mod tests {
412    //#[test]
413    //#[ignore] // Need a spawn in a spawn.
414    //fn xdotool_type_text() {
415    //    println!("");
416    //    println!("");
417    //    let text_vec = vec![
418    //         r#""$(printf 'cd $HOME && fzf \n ')""#.to_string(),
419    //         r#""$(printf '1\n ')""#.to_string(),
420    //         r#""$(printf 'cd - \n ')""#.to_string(),
421    //    ];
422    //    let spawn = super::parent_shell::type_text_spawn(text_vec, 50);
423    //    spawn.join();
424    //}
425
426    //#[test]
427    //#[ignore]//play
428    //fn termion_key() {
429	//    let test_spawn = thread::spawn(move || {
430    //        super::input_n_display::read_char()
431	//    });
432
433    //    //let spawn = super::parent_shell::type_text_spawn(vec![r#""$(printf 'q \n ')""#.to_string()], 200);
434
435    //    test_spawn.join();
436    //    //spawn.join();
437    //}
438
439    //#[test]
440    //#[ignore]//play
441    //fn termion_async_key() {
442	//    let test_spawn = thread::spawn(move || {
443    //        super::input_n_display::read_char_async()
444	//    });
445
446    //    //let spawn = super::parent_shell::type_text_spawn(vec![r#""$(printf 'q \n ')""#.to_string()], 200);
447
448    //    test_spawn.join();
449    //    //spawn.join();
450    //}
451
452    #[test]
453    #[ignore]//docker
454    fn tterminal_size_with_termion() {
455        let (w, h) = super::input_n_display::size();
456        println!("\nwidth: {}\nheight: {}", w, h);
457    }
458    #[test]
459    #[ignore]//play
460    fn takes_input_read() {
461        println!("");
462        let spawn = super::parent_shell::type_text_spawn(vec![r#""$(printf 'hello \n ')""#.to_string()], 200);
463        spawn.join().expect("failed to spawn thread");
464        super::input_n_display::read().expect("failed to read input");
465    }
466
467    #[test]
468    #[ignore]//docker
469    fn display_grid() {
470        println!("");
471        println!("");
472        super::grid_display::grid();
473        super::grid_display::grid_no_borrow()
474    }
475
476    #[test]
477    #[ignore]//docker
478    fn terminal_grid() {
479        let entry = "entry".to_string();
480
481        let mut entries: Vec<String> = vec![];
482
483        for _ in 0..49 {
484            entries.push(entry.clone())
485        }
486        println!("");
487        super::input_n_display::grid_display(entries);
488    }
489}