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) -> 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) -> thread::JoinHandle<()> {
28 let type_text = thread::spawn(move || {
30 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 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::{GridOptions, Direction, 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 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 fn write(some_stuff: &[u8], stdout: &mut RawTerminal<StdoutLock>, input_string: String) {
140 write!(
143 stdout,
144 "{}\n\r",std::str::from_utf8(&some_stuff).unwrap(),
145
146 ).unwrap();
147 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 _ => {
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 _ => 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 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 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>) {
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().unwrap();
317 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]
453 #[ignore]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]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]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]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}