foundry_debugger/
debugger.rs1use crate::{DebugNode, DebuggerBuilder, ExitReason, tui::TUI};
4use alloy_primitives::map::AddressHashMap;
5use clap::ValueEnum;
6use eyre::Result;
7use foundry_evm_core::Breakpoints;
8use foundry_evm_traces::debug::ContractSources;
9use std::path::Path;
10
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, ValueEnum)]
13pub enum DebuggerLayout {
14 #[default]
16 Auto,
17 Horizontal,
19 Vertical,
21}
22
23impl DebuggerLayout {
24 pub(crate) const fn next(self) -> Self {
25 match self {
26 Self::Auto | Self::Vertical => Self::Horizontal,
27 Self::Horizontal => Self::Vertical,
28 }
29 }
30
31 pub(crate) const fn as_str(self) -> &'static str {
32 match self {
33 Self::Auto => "auto",
34 Self::Horizontal => "horizontal",
35 Self::Vertical => "vertical",
36 }
37 }
38}
39
40#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
41pub struct DebuggerStats {
42 pub session_trace_gas_used: u64,
44 pub session_subcalls: usize,
46}
47
48pub struct DebuggerContext {
49 pub debug_arena: Vec<DebugNode>,
50 pub stats: Option<DebuggerStats>,
51 pub identified_contracts: AddressHashMap<String>,
52 pub contracts_sources: ContractSources,
54 pub breakpoints: Breakpoints,
55 pub layout: DebuggerLayout,
56}
57
58pub struct Debugger {
59 context: DebuggerContext,
60}
61
62impl Debugger {
63 #[inline]
65 pub fn builder() -> DebuggerBuilder {
66 DebuggerBuilder::new()
67 }
68
69 pub const fn new(
71 debug_arena: Vec<DebugNode>,
72 identified_contracts: AddressHashMap<String>,
73 contracts_sources: ContractSources,
74 breakpoints: Breakpoints,
75 ) -> Self {
76 Self {
77 context: DebuggerContext {
78 debug_arena,
79 stats: None,
80 identified_contracts,
81 contracts_sources,
82 breakpoints,
83 layout: DebuggerLayout::Auto,
84 },
85 }
86 }
87
88 pub(crate) const fn new_with_stats(
89 debug_arena: Vec<DebugNode>,
90 stats: DebuggerStats,
91 identified_contracts: AddressHashMap<String>,
92 contracts_sources: ContractSources,
93 breakpoints: Breakpoints,
94 layout: DebuggerLayout,
95 ) -> Self {
96 Self {
97 context: DebuggerContext {
98 debug_arena,
99 stats: Some(stats),
100 identified_contracts,
101 contracts_sources,
102 breakpoints,
103 layout,
104 },
105 }
106 }
107
108 pub fn run_tui_exit(mut self) -> ! {
110 let code = match self.try_run_tui() {
111 Ok(ExitReason::CharExit) => 0,
112 Err(e) => {
113 let _ = sh_eprintln!("{e}");
114 1
115 }
116 };
117 std::process::exit(code)
118 }
119
120 pub fn try_run_tui(&mut self) -> Result<ExitReason> {
122 eyre::ensure!(!self.context.debug_arena.is_empty(), "debug arena is empty");
123
124 let mut tui = TUI::new(&mut self.context);
125 tui.try_run()
126 }
127
128 pub fn dump_to_file(&mut self, path: &Path) -> Result<()> {
130 eyre::ensure!(!self.context.debug_arena.is_empty(), "debug arena is empty");
131 crate::dump::dump(path, &self.context)
132 }
133}