Skip to main content

marser_trace_viewer/
lib.rs

1//! AI assistance: this file was written with AI assistance. The maintainer reviewed it and did not find errors.
2//!
3//! TUI and replay helpers for marser trace logs.
4//!
5//! **Experimental:** UI and replay APIs may change between releases; see the crate
6//! README on GitHub for the current stability note.
7
8mod app;
9mod marker_index;
10pub mod outcome;
11pub mod replay;
12mod state;
13mod ui;
14
15use std::io;
16use std::path::PathBuf;
17
18pub use marser_trace_schema::TraceFormat;
19
20enum ParseArgs {
21    Run {
22        trace_path: PathBuf,
23        source_path: Option<PathBuf>,
24        format: Option<TraceFormat>,
25    },
26    Help,
27}
28
29/// Run the viewer after parsing the same CLI as the `marser-trace-viewer` binary.
30pub fn run_cli() -> io::Result<()> {
31    let program = std::env::args()
32        .next()
33        .unwrap_or_else(|| "marser-trace-viewer".to_string());
34    let args = std::env::args().skip(1);
35    let parsed = match parse_args(args) {
36        Ok(v) => v,
37        Err(err) => {
38            eprintln!("{err}\n\n{}", usage(&program));
39            std::process::exit(2);
40        }
41    };
42    match parsed {
43        ParseArgs::Help => {
44            println!("{}", usage(&program));
45            std::process::exit(0);
46        }
47        ParseArgs::Run {
48            trace_path,
49            source_path,
50            format,
51        } => app::run(trace_path, source_path, format),
52    }
53}
54
55fn usage(program: &str) -> String {
56    format!(
57        "Usage: {program} --trace <path> [--source <path>] [--format json|jsonl]\n\n\
58         Keys: i(step-into) s(step-over) u(step-up)\n\
59               backspace(previous displayed event) q(quit)"
60    )
61}
62
63fn parse_args(mut args: impl Iterator<Item = String>) -> Result<ParseArgs, String> {
64    let mut trace = None;
65    let mut source = None;
66    let mut format = None;
67    while let Some(arg) = args.next() {
68        match arg.as_str() {
69            "--help" | "-h" => return Ok(ParseArgs::Help),
70            "--trace" => trace = args.next().map(PathBuf::from),
71            "--source" => source = args.next().map(PathBuf::from),
72            "--format" => {
73                format = match args.next().as_deref() {
74                    Some("json") => Some(TraceFormat::Json),
75                    Some("jsonl") => Some(TraceFormat::Jsonl),
76                    _ => return Err("Invalid format. Use json or jsonl".to_string()),
77                }
78            }
79            _ => return Err(format!("Unknown argument: {arg}")),
80        }
81    }
82    let trace = trace.ok_or_else(|| "Missing required --trace <path>".to_string())?;
83    Ok(ParseArgs::Run {
84        trace_path: trace,
85        source_path: source,
86        format,
87    })
88}