Skip to main content

tinywasm_cli/
cli.rs

1use clap::{
2    Args, Parser, Subcommand, ValueEnum,
3    builder::{
4        Styles,
5        styling::{AnsiColor, Effects},
6    },
7};
8use clap_complete::Shell;
9
10use crate::engine_flags::EngineFlags;
11
12// based on https://github.com/crate-ci/clap-cargo/blob/master/src/style.rs
13const STYLES: Styles = Styles::styled()
14    .header(AnsiColor::BrightGreen.on_default().effects(Effects::BOLD))
15    .usage(AnsiColor::BrightGreen.on_default().effects(Effects::BOLD))
16    .literal(AnsiColor::BrightCyan.on_default().effects(Effects::BOLD))
17    .placeholder(AnsiColor::Cyan.on_default())
18    .error(AnsiColor::BrightRed.on_default().effects(Effects::BOLD))
19    .valid(AnsiColor::BrightCyan.on_default().effects(Effects::BOLD))
20    .invalid(AnsiColor::Yellow.on_default());
21
22#[derive(Parser)]
23#[command(
24    name = "tinywasm",
25    about = "TinyWasm CLI",
26    styles = STYLES,
27    version,
28    args_conflicts_with_subcommands = true,
29    subcommand_negates_reqs = true
30)]
31pub struct Cli {
32    #[arg(long, global = true, value_enum, default_value_t = LogLevel::Info)]
33    pub log_level: LogLevel,
34
35    #[command(subcommand)]
36    pub command: Option<Commands>,
37
38    #[command(flatten)]
39    pub run: RunArgs,
40}
41
42#[derive(Subcommand)]
43pub enum Commands {
44    /// Run a module
45    Run(RunArgs),
46    /// Compile a Wasm/WAT module to a .twasm archive
47    Compile(CompileArgs),
48    /// Dump lowered TinyWasm bytecode
49    Dump(ModuleInputArgs),
50    /// Inspect imports and exports
51    Inspect(ModuleInputArgs),
52    #[cfg(feature = "wast")]
53    /// Execute WebAssembly spec scripts (.wast)
54    Wast(WastArgs),
55    /// Generate shell completions
56    Completion(CompletionArgs),
57}
58
59#[derive(Args, Clone)]
60pub struct RunArgs {
61    /// Module path, or `-` to read from stdin
62    pub module: Option<String>,
63
64    /// Invoke a named export instead of the default entrypoint
65    #[arg(long)]
66    pub invoke: Option<String>,
67
68    #[command(flatten)]
69    pub engine: EngineFlags,
70
71    /// Arguments passed to the invoked Wasm function
72    #[arg(trailing_var_arg = true)]
73    pub args: Vec<String>,
74}
75
76#[derive(Args, Clone)]
77pub struct CompileArgs {
78    /// Input module path, or `-` to read from stdin
79    pub input: String,
80
81    /// Output path, or `-` to write to stdout
82    #[arg(short, long)]
83    pub output: Option<String>,
84
85    /// Overwrite the output file if it already exists
86    #[arg(short, long)]
87    pub force: bool,
88}
89
90#[derive(Args, Clone)]
91pub struct ModuleInputArgs {
92    /// Module path, or `-` to read from stdin
93    pub module: String,
94}
95
96#[derive(Args, Clone)]
97pub struct CompletionArgs {
98    pub shell: Shell,
99}
100
101#[cfg(feature = "wast")]
102#[derive(Args, Clone)]
103pub struct WastArgs {
104    /// WAST files or directories containing .wast files
105    #[arg(required = true)]
106    pub paths: Vec<String>,
107}
108
109#[derive(Clone, Copy, ValueEnum)]
110pub enum LogLevel {
111    Trace,
112    Debug,
113    Info,
114    Warn,
115    Error,
116}
117
118impl From<LogLevel> for log::LevelFilter {
119    fn from(value: LogLevel) -> Self {
120        match value {
121            LogLevel::Trace => log::LevelFilter::Trace,
122            LogLevel::Debug => log::LevelFilter::Debug,
123            LogLevel::Info => log::LevelFilter::Info,
124            LogLevel::Warn => log::LevelFilter::Warn,
125            LogLevel::Error => log::LevelFilter::Error,
126        }
127    }
128}