use clap::Args;
use crossterm::{
event::{read, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyModifiers, MouseEventKind},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{
backend::CrosstermBackend,
widgets::StatefulWidget,
Terminal,
};
use hefesto_widgets::{TextInputPopup, TextInputState};
use crate::{keybinds, style};
const INPUT_GUIDE: &str = include_str!("../INPUT_GUIDE.md");
#[derive(Args)]
pub struct InputArgs {
#[arg(short, long, default_value = "Input")]
pub prompt: String,
#[arg(short = 'W', long, default_value = "0")]
pub width: u16,
#[arg(short = 'v', long, default_value = "")]
pub value: String,
#[arg(long)]
pub guide: bool,
}
pub fn run(args: InputArgs) {
if args.guide {
println!("{}", INPUT_GUIDE);
return;
}
let mut tty: Box<dyn std::io::Write> = match std::fs::OpenOptions::new().write(true).open("/dev/tty") {
Ok(f) => Box::new(f),
Err(_) => Box::new(std::io::stdout()),
};
if enable_raw_mode().is_err() || execute!(tty, EnterAlternateScreen, EnableMouseCapture).is_err() {
eprintln!("{} input: el terminal no es interactivo", crate::BIN_NAME);
std::process::exit(1);
}
let mut terminal = Terminal::new(CrosstermBackend::new(tty)).unwrap();
terminal.clear().unwrap();
terminal.hide_cursor().unwrap();
let prompt = args.prompt.as_str();
let mut state = TextInputState {
content: args.value.clone(),
cursor: args.value.len(),
};
let mut result: Option<String> = None;
while result.is_none() {
let popup = TextInputPopup::new()
.title(&prompt)
.text_style(ratatui::style::Style::new().fg(style::TEXT))
.cursor_style(ratatui::style::Style::new().fg(style::ACCENT))
.fill_bg(style::FILL);
terminal
.draw(|frame| {
StatefulWidget::render(popup, frame.area(), frame.buffer_mut(), &mut state);
})
.unwrap();
match read().unwrap() {
Event::Key(key) => {
if key.code == keybinds::EMERGENCY && key.modifiers == KeyModifiers::CONTROL {
break;
}
match key.code {
keybinds::CONFIRM => {
result = Some(state.content.clone());
}
keybinds::CANCEL | keybinds::CANCEL_ALT => {
break;
}
keybinds::FILTER_BACKSPACE => state.delete_before(),
keybinds::FILTER_LEFT => state.cursor_left(),
keybinds::FILTER_RIGHT => state.cursor_right(),
keybinds::FILTER_HOME => state.cursor_home(),
keybinds::FILTER_END => state.cursor_end(),
KeyCode::Char(c) => state.insert_char(c),
_ => {}
}
}
Event::Mouse(mouse) => {
if mouse.kind == MouseEventKind::Down(crossterm::event::MouseButton::Left) {
}
}
_ => {}
}
}
disable_raw_mode().unwrap();
execute!(terminal.backend_mut(), LeaveAlternateScreen, DisableMouseCapture).unwrap();
terminal.show_cursor().unwrap();
if let Some(text) = result {
println!("{}", text);
std::process::exit(0);
}
std::process::exit(1);
}