168 lines
5.1 KiB
Rust
168 lines
5.1 KiB
Rust
use crate::result::AppResult;
|
|
use crate::config::get_matched_files;
|
|
use termion::input::TermRead;
|
|
use std::io::{Write, stdout, stdin, Stdout};
|
|
use termion::event::Key;
|
|
use termion::raw::{IntoRawMode, RawTerminal};
|
|
use term_grid::{Grid, GridOptions, Filling, Direction, Cell};
|
|
use std::process::exit;
|
|
use std::str::FromStr;
|
|
|
|
pub fn get_matched_files_grid(pattern: String) -> AppResult<String> {
|
|
let mut grid = Grid::new(GridOptions {
|
|
direction: Direction::LeftToRight,
|
|
filling: Filling::Spaces(2),
|
|
});
|
|
let filenames = get_matched_files(pattern).unwrap_or_else(|_| Vec::new());
|
|
for filename in filenames {
|
|
grid.add(Cell::from(filename))
|
|
}
|
|
Ok(format!("{}", grid.fit_into_columns(6)))
|
|
}
|
|
|
|
pub fn choose_pattern(current_pattern: String) -> AppResult<String> {
|
|
let mut stdout = stdout().into_raw_mode()?;
|
|
let res = read_tty_line(
|
|
&mut stdout,
|
|
"How can we recognize files? Enter filename regex.",
|
|
current_pattern,
|
|
|stdout, pattern| {
|
|
if !pattern.is_empty() {
|
|
write!(stdout, "{}------Matched files------", termion::cursor::Goto(1, 3))?;
|
|
let grid = get_matched_files_grid(pattern)?;
|
|
if grid.is_empty() {
|
|
write!(stdout, "{}No matches found",
|
|
termion::cursor::Goto(1, 4)
|
|
)?;
|
|
} else {
|
|
write!(stdout, "{}{}",
|
|
termion::cursor::Goto(1, 4),
|
|
grid
|
|
)?;
|
|
}
|
|
}
|
|
Ok(())
|
|
},
|
|
);
|
|
stdout.suspend_raw_mode()?;
|
|
res
|
|
}
|
|
|
|
pub fn choose_command(current_command: String) -> AppResult<String> {
|
|
let mut stdout = stdout().into_raw_mode()?;
|
|
let res = read_tty_line(
|
|
&mut stdout,
|
|
"Command to execute files.",
|
|
current_command,
|
|
|_, _| { Ok(()) },
|
|
);
|
|
stdout.suspend_raw_mode()?;
|
|
res
|
|
}
|
|
|
|
pub fn choose_episode(current_episode: usize) -> AppResult<usize> {
|
|
let mut stdout = stdout().into_raw_mode()?;
|
|
let res = read_tty_line(
|
|
&mut stdout,
|
|
"Choose episode.",
|
|
format!("{}", current_episode),
|
|
|_, _| { Ok(()) },
|
|
).map(|s| {
|
|
usize::from_str(s.as_str()).unwrap_or_else(|_| current_episode)
|
|
});
|
|
stdout.suspend_raw_mode()?;
|
|
res
|
|
}
|
|
|
|
|
|
pub fn read_tty_line(
|
|
stdout: &mut RawTerminal<Stdout>,
|
|
prompt: &str,
|
|
current_value: String,
|
|
after_key_press: fn(&mut RawTerminal<Stdout>, String) -> AppResult<()>,
|
|
) -> AppResult<String> {
|
|
let stdin = stdin();
|
|
// Get the standard output stream and go to raw mode.
|
|
|
|
write!(stdout, "{}{}{}{}",
|
|
termion::clear::All,
|
|
termion::cursor::Goto(1, 1),
|
|
prompt,
|
|
termion::cursor::Goto(1, 2)
|
|
)?;
|
|
// Flush stdout (i.e. make the output appear).
|
|
stdout.flush()?;
|
|
let mut buffer = current_value;
|
|
let mut current_pos = buffer.len() + 1;
|
|
if !buffer.is_empty() {
|
|
write!(stdout, "{}{}{}",
|
|
termion::cursor::Goto(1, 2),
|
|
termion::clear::AfterCursor,
|
|
buffer)?;
|
|
after_key_press(stdout, buffer.clone())?;
|
|
write!(stdout, "{}",
|
|
termion::cursor::Goto(current_pos as u16, 2)
|
|
)?;
|
|
stdout.flush()?;
|
|
}
|
|
for c in stdin.keys() {
|
|
match c? {
|
|
// Exit if \n.
|
|
Key::Char('\n') => {
|
|
break;
|
|
}
|
|
// Update pattern
|
|
Key::Char(c) => {
|
|
buffer.insert(current_pos - 1, c.clone());
|
|
current_pos += 1;
|
|
println!("{:#?}", c);
|
|
}
|
|
Key::Backspace => {
|
|
if let Some(pos) = current_pos.checked_sub(2) {
|
|
current_pos = pos + 1;
|
|
buffer.remove(pos);
|
|
}
|
|
}
|
|
Key::Delete => {
|
|
if current_pos <= buffer.len() {
|
|
buffer.remove(current_pos - 1);
|
|
}
|
|
}
|
|
Key::Right => {
|
|
if current_pos <= buffer.len() {
|
|
current_pos += 1;
|
|
}
|
|
}
|
|
Key::Left => {
|
|
if let Some(pos) = current_pos.checked_sub(1) {
|
|
current_pos = pos;
|
|
}
|
|
}
|
|
Key::Ctrl('c') => {
|
|
write!(stdout, "{}", termion::cursor::Show)?;
|
|
stdout.suspend_raw_mode()?;
|
|
exit(0);
|
|
}
|
|
Key::Ctrl('u') => {
|
|
buffer.clear();
|
|
current_pos = 1;
|
|
}
|
|
_ => {}
|
|
}
|
|
// Clear the current line.
|
|
write!(stdout, "{}{}{}",
|
|
termion::cursor::Goto(1, 2),
|
|
termion::clear::AfterCursor,
|
|
buffer)?;
|
|
// Print matched files
|
|
after_key_press(stdout, buffer.clone())?;
|
|
write!(stdout, "{}",
|
|
termion::cursor::Goto(current_pos as u16, 2)
|
|
)?;
|
|
stdout.flush()?;
|
|
}
|
|
write!(stdout, "{}{}", termion::clear::All, termion::cursor::Goto(1, 1))?;
|
|
stdout.flush()?;
|
|
// Show the cursor again before we exit.
|
|
Ok(buffer)
|
|
} |