use clap::{load_yaml, App, ArgMatches};
use std::io;
use crossterm::event::{Event, KeyCode};
use tui::backend::{Backend, CrosstermBackend};
use tui::layout::{Constraint, Direction, Layout, Rect};
use tui::widgets::{Block, Borders};
use tui::Terminal;
use tui_clap::{Events, TuiClap};
fn main() -> Result<(), io::Error> {
let yaml = load_yaml!("cli.yaml");
let app = App::from(yaml);
let stdout = io::stdout();
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let mut tui = TuiClap::from_app(app);
tui.input_widget().prompt("prompt > ");
terminal.clear().expect("Could not clear terminal");
let events = Events::default();
loop {
draw(&mut terminal, &mut tui)?;
handle_input(&mut tui, &events)
}
}
fn handle_input(tui: &mut TuiClap, events: &Events) {
if let Ok(Some(Event::Key(key_event))) = events.next() {
match key_event.code {
KeyCode::Backspace => {
tui.state().del_char()
}
KeyCode::Enter => {
if let Ok(matches) = tui.parse() {
match handle_matches(matches) {
Ok(output) => {
for message in output {
tui.write_to_output(message)
}
}
Err(err) => tui.write_to_output(err)
}
}
}
KeyCode::Char(char) => {
tui.state().add_char(char)
},
_ => {}
}
}
}
fn draw<B: Backend>(terminal: &mut Terminal<B>, tui: &mut TuiClap) -> io::Result<()> {
terminal.draw(|f| {
let chunks = Layout::default()
.direction(Direction::Vertical)
.margin(1)
.constraints(
[
Constraint::Percentage(10),
Constraint::Percentage(80),
Constraint::Percentage(10),
]
.as_ref(),
)
.split(f.size());
let block = Block::default().title("Block").borders(Borders::ALL);
f.render_widget(block, chunks[0]);
let chunks_output = Layout::default()
.direction(Direction::Horizontal)
.margin(1)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(chunks[1]);
let block = Block::default().title("Block 2").borders(Borders::ALL);
f.render_widget(block, chunks_output[0]);
let inset_area = edge_inset(&chunks_output[0], 1);
tui.render_output(f, inset_area);
let block = Block::default().title("Command").borders(Borders::ALL);
f.render_widget(block, chunks[2]);
let inset_area = edge_inset(&chunks[2], 1);
tui.render_input(f, inset_area);
})?;
Ok(())
}
fn edge_inset(area: &Rect, margin: u16) -> Rect {
let mut inset_area = *area;
inset_area.x += margin;
inset_area.y += margin;
inset_area.height -= margin;
inset_area.width -= margin;
inset_area
}
fn handle_matches(matches: ArgMatches) -> Result<Vec<String>, String> {
let mut output = vec![];
let config = matches.value_of("config").unwrap_or("default.conf");
let out = format!("Value for config: {}", config);
output.push(out);
let out = format!("Using input file: {}", matches.value_of("INPUT").unwrap());
output.push(out);
let out = match matches.occurrences_of("v") {
0 => "No verbose info".to_string(),
1 => "Some verbose info".to_string(),
2 => "Tons of verbose info".to_string(),
_ => "Don't be crazy".to_string(),
};
output.push(out);
if let Some(matches) = matches.subcommand_matches("test") {
if matches.is_present("debug") {
let out = "Printing debug info...".to_string();
output.push(out);
} else {
let out = "Printing normally...".to_string();
output.push(out);
}
};
Ok(output)
}