use clap::parser::ValueSource;
use clap::{ArgMatches, Parser, Subcommand};
use runmat_config::{PlotBackend, PlotMode};
use runmat_server_client::auth::CredentialStoreMode;
use std::path::PathBuf;
use uuid::Uuid;
use crate::cli::parse::{parse_bool_env, parse_figure_size, parse_log_level_env};
use crate::cli::remote::{FsCommand, OrgCommand, ProjectCommand, RemoteCommand};
use crate::cli::value_types::{
CaptureFiguresMode, CompressionAlg, FigureSize, GcPreset, LogLevel, OptLevel,
};
#[derive(Parser, Clone)]
#[command(
name = "runmat",
version = env!("CARGO_PKG_VERSION"),
about = "High-performance MATLAB/Octave code runtime",
long_about = r#"
RunMat is a modern, high-performance runtime for MATLAB/Octave.
It is built in Rust, and features a V8-inspired tiered execution model with a
baseline interpreter feeding an optimizing JIT compiler built on Cranelift.
Key features:
• JIT compilation with Cranelift for optimal performance
• Generational garbage collection with configurable policies
• High-performance BLAS/LAPACK operations
• Jupyter kernel protocol support with async execution
• Fast startup with snapshotting capabilities
• World-class error messages and debugging
• Compatible with MATLAB/Octave syntax and semantics
Performance Features:
• Multi-tier execution: interpreter + JIT compiler
• Adaptive optimization based on hotspot profiling
• Generational GC with write barriers and concurrent collection
• SIMD-optimized mathematical operations
• Zero-copy memory management where possible
Examples:
runmat # Start interactive REPL with JIT
runmat --no-jit # Start REPL with interpreter only
runmat --gc-preset low-latency # Optimize GC for low latency
runmat script.m # Execute MATLAB/Octave script
runmat --emit-bytecode script.m # Emit bytecode disassembly
runmat --install-kernel # Install as Jupyter kernel
runmat kernel # Start Jupyter kernel
runmat kernel-connection connection.json # Start with connection file
runmat version --detailed # Show detailed version information
"#,
after_help = r#"
Environment Variables:
RUNMAT_DEBUG=1 Enable debug logging
RUNMAT_LOG_LEVEL=debug Set log level (error, warn, info, debug, trace)
RUNMAT_KERNEL_IP=127.0.0.1 Kernel IP address
RUNMAT_KERNEL_KEY=<key> Kernel authentication key
RUNMAT_TIMEOUT=300 Execution timeout in seconds
RUNMAT_CALLSTACK_LIMIT=200 Maximum call stack frames to record
RUNMAT_ERROR_NAMESPACE=RunMat Error identifier namespace prefix override
RUNMAT_CONFIG=<path> Path to configuration file
RUNMAT_SNAPSHOT_PATH=<path> Snapshot file to preload standard library
Garbage Collector:
RUNMAT_GC_PRESET=<preset> GC preset (low-latency, high-throughput, low-memory, debug)
RUNMAT_GC_YOUNG_SIZE=<mb> Young generation size in MB
RUNMAT_GC_THREADS=<n> Number of GC threads
JIT Compiler:
RUNMAT_JIT_ENABLE=1 Enable JIT compilation (default: true)
RUNMAT_JIT_THRESHOLD=<n> JIT compilation threshold (default: 10)
RUNMAT_JIT_OPT_LEVEL=<level> JIT optimization level (none, size, speed, aggressive; default: speed)
For more information, visit: https://github.com/runmat-org/runmat
"#
)]
#[command(propagate_version = true)]
pub struct Cli {
#[arg(short, long, env = "RUNMAT_DEBUG", value_parser = parse_bool_env)]
pub debug: bool,
#[arg(long, value_enum, env = "RUNMAT_LOG_LEVEL", default_value = "warn", value_parser = parse_log_level_env)]
pub log_level: LogLevel,
#[arg(long, env = "RUNMAT_TIMEOUT", default_value = "300")]
pub timeout: u64,
#[arg(long, env = "RUNMAT_CALLSTACK_LIMIT", default_value = "200")]
pub callstack_limit: usize,
#[arg(long, value_name = "PATH", num_args = 0..=1, default_missing_value = "-")]
pub emit_bytecode: Option<PathBuf>,
#[arg(long, env = "RUNMAT_ERROR_NAMESPACE")]
pub error_namespace: Option<String>,
#[arg(long, env = "RUNMAT_CONFIG")]
pub config: Option<PathBuf>,
#[arg(long, env = "RUNMAT_JIT_DISABLE", value_parser = parse_bool_env)]
pub no_jit: bool,
#[arg(long, env = "RUNMAT_JIT_THRESHOLD", default_value = "10")]
pub jit_threshold: u32,
#[arg(
long,
value_enum,
env = "RUNMAT_JIT_OPT_LEVEL",
default_value = "speed"
)]
pub jit_opt_level: OptLevel,
#[arg(long, value_enum, env = "RUNMAT_GC_PRESET")]
pub gc_preset: Option<GcPreset>,
#[arg(long, env = "RUNMAT_GC_YOUNG_SIZE")]
pub gc_young_size: Option<usize>,
#[arg(long, env = "RUNMAT_GC_THREADS")]
pub gc_threads: Option<usize>,
#[arg(long, env = "RUNMAT_GC_STATS", value_parser = parse_bool_env)]
pub gc_stats: bool,
#[arg(short, long)]
pub verbose: bool,
#[arg(long, env = "RUNMAT_SNAPSHOT_PATH")]
pub snapshot: Option<PathBuf>,
#[arg(long, value_enum, env = "RUNMAT_PLOT_MODE")]
pub plot_mode: Option<PlotMode>,
#[arg(long, env = "RUNMAT_PLOT_HEADLESS", value_parser = parse_bool_env)]
pub plot_headless: bool,
#[arg(long, value_enum, env = "RUNMAT_PLOT_BACKEND")]
pub plot_backend: Option<PlotBackend>,
#[arg(long)]
pub plot_scatter_target: Option<u32>,
#[arg(long)]
pub plot_surface_vertex_budget: Option<u64>,
#[arg(long, env = "RUNMAT_ARTIFACTS_DIR")]
pub artifacts_dir: Option<PathBuf>,
#[arg(long, env = "RUNMAT_ARTIFACTS_MANIFEST")]
pub artifacts_manifest: Option<PathBuf>,
#[arg(
long,
value_enum,
env = "RUNMAT_CAPTURE_FIGURES",
default_value = "auto"
)]
pub capture_figures: CaptureFiguresMode,
#[arg(long, env = "RUNMAT_FIGURE_SIZE", default_value = "1280x720", value_parser = parse_figure_size)]
pub figure_size: FigureSize,
#[arg(long, env = "RUNMAT_MAX_FIGURES", default_value = "8")]
pub max_figures: usize,
#[arg(long)]
pub generate_config: bool,
#[arg(long)]
pub install_kernel: bool,
#[command(subcommand)]
pub command: Option<Commands>,
pub script: Option<PathBuf>,
}
#[derive(Clone, Debug, Default)]
pub struct CliOverrideSources {
pub debug: bool,
pub log_level: bool,
pub timeout: bool,
pub callstack_limit: bool,
pub jit_threshold: bool,
pub jit_opt_level: bool,
pub gc_stats: bool,
pub verbose: bool,
}
impl CliOverrideSources {
pub fn from_matches(matches: &ArgMatches) -> Self {
Self {
debug: Self::was_provided(matches, "debug"),
log_level: Self::was_provided(matches, "log_level"),
timeout: Self::was_provided(matches, "timeout"),
callstack_limit: Self::was_provided(matches, "callstack_limit"),
jit_threshold: Self::was_provided(matches, "jit_threshold"),
jit_opt_level: Self::was_provided(matches, "jit_opt_level"),
gc_stats: Self::was_provided(matches, "gc_stats"),
verbose: Self::was_provided(matches, "verbose"),
}
}
fn was_provided(matches: &ArgMatches, id: &str) -> bool {
matches
.value_source(id)
.is_some_and(|source| source != ValueSource::DefaultValue)
}
}
#[derive(Subcommand, Clone)]
pub enum Commands {
Repl {
#[arg(short, long)]
verbose: bool,
},
Kernel {
#[arg(long, env = "RUNMAT_KERNEL_IP", default_value = "127.0.0.1")]
ip: String,
#[arg(long, env = "RUNMAT_KERNEL_KEY")]
key: Option<String>,
#[arg(long, default_value = "tcp")]
transport: String,
#[arg(long, default_value = "hmac-sha256")]
signature_scheme: String,
#[arg(long, env = "RUNMAT_SHELL_PORT", default_value = "0")]
shell_port: u16,
#[arg(long, env = "RUNMAT_IOPUB_PORT", default_value = "0")]
iopub_port: u16,
#[arg(long, env = "RUNMAT_STDIN_PORT", default_value = "0")]
stdin_port: u16,
#[arg(long, env = "RUNMAT_CONTROL_PORT", default_value = "0")]
control_port: u16,
#[arg(long, env = "RUNMAT_HB_PORT", default_value = "0")]
hb_port: u16,
#[arg(long)]
connection_file: Option<PathBuf>,
},
KernelConnection {
connection_file: PathBuf,
},
Run {
file: PathBuf,
#[arg(last = true)]
args: Vec<String>,
},
Version {
#[arg(long)]
detailed: bool,
},
Info,
AccelInfo {
#[arg(long)]
json: bool,
#[arg(long)]
reset: bool,
},
#[cfg(feature = "wgpu")]
AccelCalibrate {
input: PathBuf,
#[arg(long)]
dry_run: bool,
#[arg(long)]
json: bool,
},
Gc {
#[command(subcommand)]
gc_command: GcCommand,
},
Benchmark {
file: PathBuf,
#[arg(short, long, default_value = "10")]
iterations: u32,
#[arg(long)]
jit: bool,
},
Snapshot {
#[command(subcommand)]
snapshot_command: SnapshotCommand,
},
Config {
#[command(subcommand)]
config_command: ConfigCommand,
},
Remote {
#[command(subcommand)]
remote_command: RemoteCommand,
},
Login {
#[arg(long)]
server: Option<String>,
#[arg(long)]
api_key: Option<String>,
#[arg(long)]
email: Option<String>,
#[arg(long, default_value = "file")]
credential_store: CredentialStoreMode,
#[arg(long)]
org: Option<Uuid>,
#[arg(long)]
project: Option<Uuid>,
},
Org {
#[command(subcommand)]
org_command: OrgCommand,
},
Project {
#[command(subcommand)]
project_command: ProjectCommand,
},
Fs {
#[command(subcommand)]
fs_command: FsCommand,
},
}
#[derive(Subcommand, Clone)]
pub enum GcCommand {
Stats,
Minor,
Major,
Config,
Stress {
#[arg(short, long, default_value = "10000")]
allocations: usize,
},
}
#[derive(Subcommand, Clone)]
pub enum SnapshotCommand {
Create {
#[arg(short, long)]
output: PathBuf,
#[arg(short = 'O', long, value_enum, default_value = "speed")]
optimization: OptLevel,
#[arg(short, long, value_enum)]
compression: Option<CompressionAlg>,
},
Info {
snapshot: PathBuf,
},
Presets,
Validate {
snapshot: PathBuf,
},
}
#[derive(Subcommand, Clone)]
pub enum ConfigCommand {
Show,
Generate {
#[arg(short, long, default_value = ".runmat.yaml")]
output: PathBuf,
},
Validate {
config_file: PathBuf,
},
Paths,
}