use clap::{command, Parser};
use flamelens::app::{App, AppResult};
use flamelens::event::{Event, EventHandler};
use flamelens::flame::FlameGraph;
use flamelens::handler::handle_key_events;
use flamelens::tui::Tui;
use ratatui::backend::CrosstermBackend;
use ratatui::Terminal;
use std::io::{self, Read};
#[derive(Parser, Debug)]
#[command(version)]
struct Args {
filename: Option<String>,
#[clap(long, action, value_name = "sorted")]
sorted: bool,
#[clap(long, value_name = "pid")]
pid: Option<String>,
#[clap(long, value_name = "py-spy-args")]
py_spy_args: Option<String>,
#[clap(long)]
debug: bool,
}
fn main() -> AppResult<()> {
let args = Args::parse();
let mut app = if let Some(_pid) = args.pid {
cfg_if::cfg_if! {
if #[cfg(feature = "python")] {
App::with_pid(
_pid.parse().expect("Could not parse pid"),
args.py_spy_args.clone(),
)
} else {
panic!("--pid is only available with the 'python' feature");
}
}
} else {
let (filename, content) = if let Some(filename) = &args.filename {
(
filename.as_str(),
std::fs::read_to_string(filename).expect("Could not read file"),
)
} else {
let mut buf: Vec<u8> = Vec::new();
io::stdin()
.read_to_end(&mut buf)
.expect("Could not read stdin");
let content = String::from_utf8(buf).expect("Could not parse stdin");
("stdin", content)
};
let tic = std::time::Instant::now();
let flamegraph = FlameGraph::from_string(content, args.sorted);
let mut app = App::with_flamegraph(filename, flamegraph);
app.add_elapsed("flamegraph", tic.elapsed());
app
};
app.debug = args.debug;
let backend = CrosstermBackend::new(io::stderr());
let terminal = Terminal::new(backend)?;
let events = EventHandler::new(250);
let mut tui = Tui::new(terminal, events);
tui.init()?;
while app.running {
tui.draw(&mut app)?;
match tui.events.next()? {
Event::Tick => app.tick(),
Event::Key(key_event) => handle_key_events(key_event, &mut app)?,
Event::Mouse(_) => {}
Event::Resize(_, _) => {}
}
}
tui.exit()?;
Ok(())
}