use std::io::{stdin, stdout, Write};
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
pub fn select<'a, T: std::fmt::Display>(prompt: &str, list: &'a [T]) -> Option<&'a T> {
let stdin = stdin();
let mut stdout = stdout().into_raw_mode().unwrap();
let last_item_id = list.len() - 1;
write!(
stdout,
"{} ? {}{}{}{}\n\r",
termion::color::Fg(termion::color::Green),
termion::style::Reset,
termion::style::Bold,
prompt,
termion::style::Reset
)
.unwrap();
let mut curr = 0;
let mut input = stdin.keys();
loop {
for (i, s) in list.iter().enumerate() {
write!(stdout, "{}", termion::clear::CurrentLine).unwrap();
if curr == i {
write!(
stdout,
"{}{} {} {}{}",
termion::style::Bold,
termion::color::Fg(termion::color::Cyan),
figures_rs::POINTER,
s,
termion::style::Reset
)
.unwrap();
} else {
write!(stdout, " {}", s).unwrap();
}
write!(stdout, "\n\r").unwrap();
}
stdout.flush().unwrap();
let next = input.next().unwrap();
match next.unwrap() {
Key::Char('\n') | Key::Char('l') => {
write!(stdout, "\n\r{}", termion::cursor::Show).unwrap();
return list.get(curr);
}
Key::Up | Key::Char('k') => {
if curr == 0 {
curr = last_item_id;
} else {
curr -= 1;
}
}
Key::Down | Key::Char('j') => {
if curr == last_item_id {
curr = 0;
} else {
curr += 1;
}
}
Key::Ctrl('c') | Key::Char('q') => {
write!(stdout, "\n\r{}", termion::cursor::Show).unwrap();
return None;
}
_ => {}
};
print!("{}", termion::cursor::Up(list.len() as u16));
}
}
pub fn checkbox<'a, T: std::fmt::Display>(
prompt: &'a str,
list: &'a [T],
) -> Option<Vec<(&'a T, bool)>> {
let mut list: Vec<(&T, bool)> = list.iter().map(|item| (item, false)).collect();
let stdin = stdin();
let mut stdout = stdout().into_raw_mode().unwrap();
let last_item_id = list.len() - 1;
write!(
stdout,
"{} ? {}{}{}{}\n\r",
termion::color::Fg(termion::color::Green),
termion::style::Reset,
termion::style::Bold,
prompt,
termion::style::Reset
)
.unwrap();
let mut curr = 0;
let mut input = stdin.keys();
fn print_check<'a, T>(s: &(&T, bool)) -> &'a str {
if s.1 {
figures_rs::CIRCLE_FILLED
} else {
figures_rs::CIRCLE
}
}
loop {
for (i, s) in list.iter_mut().enumerate() {
write!(stdout, "{}", termion::clear::CurrentLine).unwrap();
if curr == i {
write!(
stdout,
"{}{} {} {} {}{}",
termion::style::Bold,
termion::color::Fg(termion::color::Cyan),
figures_rs::POINTER,
print_check(s),
s.0,
termion::style::Reset
)
.unwrap();
} else {
write!(stdout, " {} {}", print_check(s), s.0).unwrap();
}
write!(stdout, "\n\r").unwrap();
}
stdout.flush().unwrap();
let next = input.next().unwrap();
match next.unwrap() {
Key::Char('\n') | Key::Char('l') => {
write!(stdout, "\n\r{}", termion::cursor::Show).unwrap();
return Some(list);
}
Key::Char(' ') => {
list[curr].1 = !list[curr].1;
}
Key::Up | Key::Char('k') => {
if curr == 0 {
curr = last_item_id;
} else {
curr -= 1;
}
}
Key::Down | Key::Char('j') => {
if curr == last_item_id {
curr = 0;
} else {
curr += 1;
}
}
Key::Ctrl('c') | Key::Char('q') => {
write!(stdout, "\n\r{}", termion::cursor::Show).unwrap();
return None;
}
_ => {}
};
print!("{}", termion::cursor::Up(list.len() as u16));
}
}
pub fn confirm(prompt: &str) -> bool {
let stdin = stdin();
let mut stdout = stdout().into_raw_mode().unwrap();
write!(
stdout,
"{} ? {}{}{}{} (y/n) ",
termion::color::Fg(termion::color::Green),
termion::style::Reset,
termion::style::Bold,
prompt,
termion::style::Reset
)
.unwrap();
let mut curr = None;
let mut input = stdin.keys();
fn curr_to_letter(curr: &Option<bool>) -> &str {
if let Some(curr) = curr {
if *curr {
"Y"
} else {
"N"
}
} else {
" "
}
}
write!(stdout, "{}", termion::cursor::Hide).unwrap();
loop {
write!(
stdout,
"{}{}",
termion::clear::AfterCursor,
curr_to_letter(&curr)
)
.unwrap();
print!("{}", termion::cursor::Left(1));
stdout.flush().unwrap();
let next = input.next().unwrap();
match next.unwrap() {
Key::Char('\n') | Key::Char('l') => {
write!(stdout, "\n\r{}", termion::cursor::Show).unwrap();
return if let Some(true) = curr { true } else { false };
}
Key::Up | Key::Char('k') => {
if let Some(c) = curr {
curr = Some(!c);
} else {
curr = Some(false);
}
}
Key::Down | Key::Char('j') => {
if let Some(c) = curr {
curr = Some(!c);
} else {
curr = Some(true);
}
}
Key::Char('y') | Key::Char('Y') => curr = Some(true),
Key::Char('n') | Key::Char('N') => curr = Some(false),
Key::Backspace => curr = None,
Key::Ctrl('c') | Key::Char('q') => {
write!(stdout, "\n\r{}", termion::cursor::Show).unwrap();
return false;
}
_ => {}
};
}
}