chisel/
cmd.rs

1//! ChiselCommand
2//!
3//! This module holds the [ChiselCommand] enum, which contains all builtin commands that
4//! can be executed within the REPL.
5
6use crate::prelude::ChiselDispatcher;
7use std::{error::Error, str::FromStr};
8use strum::EnumIter;
9
10/// Builtin chisel command variants
11#[derive(Debug, EnumIter)]
12pub enum ChiselCommand {
13    /// Print helpful information about chisel
14    Help,
15    /// Quit the REPL
16    Quit,
17    /// Clear the current session source
18    Clear,
19    /// Print the generated source contract
20    Source,
21    /// Save the current session to the cache
22    /// Takes: `<session-id>`
23    Save,
24    /// Load a previous session from cache
25    /// Takes: `<session-id>`
26    ///
27    /// WARNING: This will overwrite the current session (though the current session will be
28    /// optimistically cached)
29    Load,
30    /// List all cached sessions
31    ListSessions,
32    /// Clear the cache of all stored sessions
33    ClearCache,
34    /// Fork an RPC in the current session
35    /// Takes <fork-url|env-var|rpc_endpoints-alias>
36    Fork,
37    /// Enable / disable traces for the current session
38    Traces,
39    /// Set calldata (`msg.data`) for the current session (appended after function selector)
40    Calldata,
41    /// Dump the raw memory
42    MemDump,
43    /// Dump the raw stack
44    StackDump,
45    /// Export the current REPL session source to a Script file
46    Export,
47    /// Fetch an interface of a verified contract on Etherscan
48    /// Takes: `<addr> <interface-name>` and optional `<chain-id>` (defaults to `1` / mainnet if
49    /// not specified).
50    Fetch,
51    /// Executes a shell command
52    Exec,
53    /// Display the raw value of a variable's stack allocation.
54    RawStack,
55    /// Open the current session in an editor
56    Edit,
57}
58
59/// Attempt to convert a string slice to a `ChiselCommand`
60impl FromStr for ChiselCommand {
61    type Err = Box<dyn Error>;
62
63    fn from_str(s: &str) -> Result<Self, Self::Err> {
64        match s.to_lowercase().as_ref() {
65            "help" | "h" => Ok(Self::Help),
66            "quit" | "q" => Ok(Self::Quit),
67            "clear" | "c" => Ok(Self::Clear),
68            "source" | "so" => Ok(Self::Source),
69            "save" | "s" => Ok(Self::Save),
70            "list" | "ls" => Ok(Self::ListSessions),
71            "load" | "l" => Ok(Self::Load),
72            "clearcache" | "cc" => Ok(Self::ClearCache),
73            "fork" | "f" => Ok(Self::Fork),
74            "traces" | "t" => Ok(Self::Traces),
75            "calldata" | "cd" => Ok(Self::Calldata),
76            "memdump" | "md" => Ok(Self::MemDump),
77            "stackdump" | "sd" => Ok(Self::StackDump),
78            "export" | "ex" => Ok(Self::Export),
79            "fetch" | "fe" => Ok(Self::Fetch),
80            "exec" | "e" => Ok(Self::Exec),
81            "rawstack" | "rs" => Ok(Self::RawStack),
82            "edit" => Ok(Self::Edit),
83            _ => Err(ChiselDispatcher::make_error(format!(
84                "Unknown command \"{s}\"! See available commands with `!help`.",
85            ))
86            .into()),
87        }
88    }
89}
90
91/// A category for [ChiselCommand]s
92#[derive(Debug, EnumIter)]
93pub enum CmdCategory {
94    /// General category
95    General,
96    /// Session category
97    Session,
98    /// Environment category
99    Env,
100    /// Debug category
101    Debug,
102}
103
104impl core::fmt::Display for CmdCategory {
105    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
106        let string = match self {
107            Self::General => "General",
108            Self::Session => "Session",
109            Self::Env => "Environment",
110            Self::Debug => "Debug",
111        };
112        f.write_str(string)
113    }
114}
115
116/// A command descriptor type
117pub type CmdDescriptor = (&'static [&'static str], &'static str, CmdCategory);
118
119/// Convert a `ChiselCommand` into a `CmdDescriptor` tuple
120impl From<ChiselCommand> for CmdDescriptor {
121    fn from(cmd: ChiselCommand) -> Self {
122        match cmd {
123            // General
124            ChiselCommand::Help => (&["help", "h"], "Display all commands", CmdCategory::General),
125            ChiselCommand::Quit => (&["quit", "q"], "Quit Chisel", CmdCategory::General),
126            ChiselCommand::Exec => (
127                &["exec <command> [args]", "e <command> [args]"],
128                "Execute a shell command and print the output",
129                CmdCategory::General,
130            ),
131            // Session
132            ChiselCommand::Clear => {
133                (&["clear", "c"], "Clear current session source", CmdCategory::Session)
134            }
135            ChiselCommand::Source => (
136                &["source", "so"],
137                "Display the source code of the current session",
138                CmdCategory::Session,
139            ),
140            ChiselCommand::Save => (
141                &["save [id]", "s [id]"],
142                "Save the current session to cache",
143                CmdCategory::Session,
144            ),
145            ChiselCommand::Load => (
146                &["load <id>", "l <id>"],
147                "Load a previous session ID from cache",
148                CmdCategory::Session,
149            ),
150            ChiselCommand::ListSessions => {
151                (&["list", "ls"], "List all cached sessions", CmdCategory::Session)
152            }
153            ChiselCommand::ClearCache => (
154                &["clearcache", "cc"],
155                "Clear the chisel cache of all stored sessions",
156                CmdCategory::Session,
157            ),
158            ChiselCommand::Export => (
159                &["export", "ex"],
160                "Export the current session source to a script file",
161                CmdCategory::Session,
162            ),
163            ChiselCommand::Fetch => (
164                &["fetch <addr> <name>", "fe <addr> <name>"],
165                "Fetch the interface of a verified contract on Etherscan",
166                CmdCategory::Session,
167            ),
168            // Environment
169            ChiselCommand::Fork => (
170                &["fork <url>", "f <url>"],
171                "Fork an RPC for the current session. Supply 0 arguments to return to a local network",
172                CmdCategory::Env,
173            ),
174            ChiselCommand::Traces => (
175                &["traces", "t"],
176                "Enable / disable traces for the current session",
177                CmdCategory::Env,
178            ),
179            ChiselCommand::Calldata => (
180                &["calldata [data]", "cd [data]"],
181                "Set calldata (`msg.data`) for the current session (appended after function selector). Clears it if no argument provided.",
182                CmdCategory::Env,
183            ),
184            // Debug
185            ChiselCommand::MemDump => {
186                (&["memdump", "md"], "Dump the raw memory of the current state", CmdCategory::Debug)
187            }
188            ChiselCommand::StackDump => (
189                &["stackdump", "sd"],
190                "Dump the raw stack of the current state",
191                CmdCategory::Debug,
192            ),
193            ChiselCommand::Edit => {
194                (&["edit"], "Open the current session in an editor", CmdCategory::Session)
195            }
196            ChiselCommand::RawStack => (
197                &["rawstack <var>", "rs <var>"],
198                "Display the raw value of a variable's stack allocation. For variables that are > 32 bytes in length, this will display their memory pointer.",
199                CmdCategory::Debug,
200            ),
201        }
202    }
203}