#![allow(dead_code)]
mod app;
mod buffer;
mod config;
mod event;
mod filter;
mod hex;
mod highlight;
mod history;
mod input;
mod logging;
mod macros;
mod mouse;
mod search;
mod serial;
mod theme;
mod ui;
use anyhow::Result;
use clap::Parser;
use crossterm::{
event::{DisableMouseCapture, EnableMouseCapture},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::prelude::*;
use std::io;
use app::App;
use event::EventLoop;
#[derive(Parser, Debug)]
#[command(name = "yapper", version, about)]
struct Cli {
#[arg(value_name = "PORT")]
port: Option<String>,
#[arg(value_name = "BAUD")]
baud: Option<u32>,
#[arg(short, long)]
data_bits: Option<u8>,
#[arg(short, long)]
parity: Option<String>,
#[arg(short, long)]
stop_bits: Option<u8>,
#[arg(short, long)]
flow_control: Option<String>,
#[arg(long)]
line_ending: Option<String>,
#[arg(long)]
no_auto: bool,
}
fn main() -> Result<()> {
let cli = Cli::parse();
let app_config = config::AppConfig::load();
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::with_options(
backend,
ratatui::TerminalOptions {
viewport: ratatui::Viewport::Fullscreen,
},
)?;
let serial_config = serial::config::SerialConfig {
baud_rate: cli.baud.unwrap_or(app_config.defaults.baud_rate),
data_bits: parse_data_bits(cli.data_bits.unwrap_or(app_config.defaults.data_bits)),
parity: parse_parity(cli.parity.as_deref().unwrap_or(&app_config.defaults.parity)),
stop_bits: parse_stop_bits(cli.stop_bits.unwrap_or(app_config.defaults.stop_bits)),
flow_control: parse_flow_control(cli.flow_control.as_deref().unwrap_or(&app_config.defaults.flow_control)),
};
let line_ending = match cli.line_ending.as_deref().unwrap_or(&app_config.defaults.line_ending) {
"lf" => "\n",
"cr" => "\r",
_ => "\r\n",
};
let mut app = App::new(serial_config, line_ending.to_string(), app_config.clone());
if let Some(port) = cli.port {
app.connect(&port);
} else if !cli.no_auto && app_config.connection.auto_connect {
if let Some(last_port) = &app_config.connection.last_port {
app.connect(last_port);
}
}
let mut event_loop = EventLoop::new();
let result = event_loop.run(&mut terminal, &mut app);
disable_raw_mode()?;
execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
terminal.show_cursor()?;
result
}
fn parse_data_bits(bits: u8) -> serialport::DataBits {
match bits {
5 => serialport::DataBits::Five,
6 => serialport::DataBits::Six,
7 => serialport::DataBits::Seven,
_ => serialport::DataBits::Eight,
}
}
fn parse_parity(parity: &str) -> serialport::Parity {
match parity.to_lowercase().as_str() {
"odd" => serialport::Parity::Odd,
"even" => serialport::Parity::Even,
_ => serialport::Parity::None,
}
}
fn parse_stop_bits(bits: u8) -> serialport::StopBits {
match bits {
2 => serialport::StopBits::Two,
_ => serialport::StopBits::One,
}
}
fn parse_flow_control(fc: &str) -> serialport::FlowControl {
match fc.to_lowercase().as_str() {
"software" | "sw" | "xon" => serialport::FlowControl::Software,
"hardware" | "hw" | "rts" => serialport::FlowControl::Hardware,
_ => serialport::FlowControl::None,
}
}