Skip to main content

miden_debug/ui/
mod.rs

1mod action;
2mod app;
3mod duration;
4mod pages;
5mod panes;
6pub(crate) mod state;
7mod syntax_highlighting;
8mod tui;
9
10use log::LevelFilter;
11use miden_assembly_syntax::diagnostics::{IntoDiagnostic, Report};
12
13pub use self::state::{DebugMode, State};
14use self::{action::Action, app::App};
15use crate::config::DebuggerConfig;
16
17#[allow(dead_code)]
18pub fn run(config: Box<DebuggerConfig>, logger: Box<dyn log::Log>) -> Result<(), Report> {
19    run_with_log_level(config, logger, LevelFilter::Trace)
20}
21
22pub fn run_with_log_level(
23    config: Box<DebuggerConfig>,
24    logger: Box<dyn log::Log>,
25    max_level: LevelFilter,
26) -> Result<(), Report> {
27    let mut builder = tokio::runtime::Builder::new_current_thread();
28    let rt = builder.enable_all().build().into_diagnostic()?;
29    rt.block_on(async move { start_ui(config, logger, max_level).await })
30}
31
32/// Launch the TUI debugger with a pre-built [State].
33///
34/// This is the programmatic entry point used by transaction debugging, where
35/// the caller constructs a [State] with pre-recorded event replay data.
36pub fn run_with_state(state: State, logger: Box<dyn log::Log>) -> Result<(), Report> {
37    run_with_state_and_log_level(state, logger, LevelFilter::Trace)
38}
39
40/// Launch the TUI debugger with a pre-built [State] and log level filter.
41pub fn run_with_state_and_log_level(
42    state: State,
43    logger: Box<dyn log::Log>,
44    max_level: LevelFilter,
45) -> Result<(), Report> {
46    let mut builder = tokio::runtime::Builder::new_current_thread();
47    let rt = builder.enable_all().build().into_diagnostic()?;
48    rt.block_on(async move { start_ui_with_state(state, logger, max_level).await })
49}
50
51#[allow(dead_code)]
52pub async fn start_ui(
53    config: Box<DebuggerConfig>,
54    logger: Box<dyn log::Log>,
55    max_level: LevelFilter,
56) -> Result<(), Report> {
57    use ratatui::crossterm as term;
58
59    crate::logger::DebugLogger::install_with_max_level(logger, max_level).into_diagnostic()?;
60
61    let original_hook = std::panic::take_hook();
62    std::panic::set_hook(Box::new(move |panic_info| {
63        let _ = term::terminal::disable_raw_mode();
64        let _ = term::execute!(std::io::stdout(), term::terminal::LeaveAlternateScreen);
65        original_hook(panic_info);
66    }));
67
68    let mut app = App::new(config).await?;
69    app.run().await?;
70
71    Ok(())
72}
73
74async fn start_ui_with_state(
75    state: State,
76    logger: Box<dyn log::Log>,
77    max_level: LevelFilter,
78) -> Result<(), Report> {
79    use ratatui::crossterm as term;
80
81    crate::logger::DebugLogger::install_with_max_level(logger, max_level).into_diagnostic()?;
82
83    let original_hook = std::panic::take_hook();
84    std::panic::set_hook(Box::new(move |panic_info| {
85        let _ = term::terminal::disable_raw_mode();
86        let _ = term::execute!(std::io::stdout(), term::terminal::LeaveAlternateScreen);
87        original_hook(panic_info);
88    }));
89
90    let mut app = App::from_state(state).await?;
91    app.run().await?;
92
93    Ok(())
94}